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']

Réponses:


241
T = [L[i] for i in Idx]

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)


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]

Cela ne fonctionnera pas s'il bne contient qu'un seul élément.
blhsing


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']

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


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']
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.