En Python, comment indexer une liste avec une autre liste?

130

Je voudrais indexer une liste avec une autre liste comme celle-ci

L = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
Idx = [0, 3, 7]
T = L[ Idx ]

et T devrait finir par être une liste contenant ['a', 'd', 'h'].

Y a-t-il un meilleur moyen que

T = []
for i in Idx:
    T.append(L[i])

print T
# Gives result ['a', 'd', 'h']
Daniel Andrén
la source

Réponses:

241
T = [L[i] for i in Idx]
van
la source
7
Est-ce plus rapide qu'une boucle for ou seulement plus courte?
Daniel Andrén
10
@daniel: both + recommended
SilentGhost
14
Un test de timing rapide (pas de pysco ou quoi que ce soit, alors faites-en ce que vous voulez) a montré la compréhension de la liste 2,5x plus vite que la boucle (1000 éléments, répétés 10000 fois).
James Hopkin
2
(l'utilisation de la carte et d'un lambda est encore plus lente - à prévoir, car elle appelle une fonction à chaque itération)
James Hopkin
+1 Si la liste d'indexation est arbitraire, alors une composition de liste est la solution. Je pense cependant que, lorsque cela est possible, ce qui ne semble pas être le cas ici, les tranches sont encore plus rapides.
Jaime
41

Si vous utilisez numpy, vous pouvez effectuer un découpage étendu comme celui-ci:

>>> import numpy
>>> a=numpy.array(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
>>> Idx = [0, 3, 7]
>>> a[Idx]
array(['a', 'd', 'h'], 
      dtype='|S1')

... et est probablement beaucoup plus rapide (si les performances sont suffisamment importantes pour se soucier de l'importation numpy)

Paul
la source
5
Mon test rapide timeit a montré que l'utilisation de np.array est en fait presque 3 fois plus lente (y compris la conversion en tableau).
Andrzej Pronobis
Cela fonctionne mieux si vous devez de toute façon le convertir pour des opérations de tableau. Trop de temps pour les opérations de liste régulières.
frankliuao
9

Une approche fonctionnelle:

a = [1,"A", 34, -123, "Hello", 12]
b = [0, 2, 5]

from operator import itemgetter

print(list(itemgetter(*b)(a)))
[1, 34, 12]
Padraic Cunningham
la source
Cela ne fonctionnera pas s'il bne contient qu'un seul élément.
blhsing
7
T = map(lambda i: L[i], Idx)
Mehrdad Afshari
la source
6
doit être converti en liste dans py3k
SilentGhost
5

Je n'étais satisfait d'aucune de ces approches, j'ai donc proposé une Flexlistclasse qui permet une indexation flexible, soit par entier, tranche ou liste d'index:

class Flexlist(list):
    def __getitem__(self, keys):
        if isinstance(keys, (int, slice)): return list.__getitem__(self, keys)
        return [self[k] for k in keys]

Lequel, pour votre exemple, vous utiliseriez comme:

L = Flexlist(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
Idx = [0, 3, 7]
T = L[ Idx ]

print(T)  # ['a', 'd', 'h']
jedwards
la source
qui démontre également la puissance et la flexibilité de Python!
crowie
Il est si facile d'étendre cela également pour le code existant. Appelez simplement existing_list = Flexlist(existing_list)et nous avons la fonctionnalité requise sans casser le code
Oui
1
L= {'a':'a','d':'d', 'h':'h'}
index= ['a','d','h'] 
for keys in index:
    print(L[keys])

J'utiliser un Dict adddésiré keyspourindex

user4749532
la source
0

Vous pouvez également utiliser la __getitem__méthode combinée avec mapcomme suit:

L = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
Idx = [0, 3, 7]
res = list(map(L.__getitem__, Idx))
print(res)
# ['a', 'd', 'h']
David S
la source