2010-07-22 4 views
61

J'essaie d'obtenir les n-ième éléments d'une liste de tuples.Comment extraire les n-ième éléments d'une liste de tuples en python?

J'ai quelque chose comme:

elements = [(1,1,1),(2,3,7),(3,5,10)] 

Je souhaite extraire uniquement les deuxièmes éléments de chaque tuple dans une liste:

seconds = [1, 3, 5] 

Je sais que cela pourrait se faire avec une boucle for mais Je voulais savoir s'il y avait un autre moyen puisque j'ai des milliers de tuples.

Répondre

123
[x[1] for x in elements] 
23

Je sais que cela pourrait être fait avec FOR mais je voulais savoir s'il y a une autre façon

Il y a une autre façon. Vous pouvez aussi le faire avec map et itemgetter:

>>> from operator import itemgetter 
>>> map(itemgetter(1), elements) 

Cette PERFORMs encore une boucle interne bien et il est légèrement plus lent que la compréhension de la liste:

setup = 'elements = [(1,1,1) for _ in range(100000)];from operator import itemgetter' 
method1 = '[x[1] for x in elements]' 
method2 = 'map(itemgetter(1), elements)' 

import timeit 
t = timeit.Timer(method1, setup) 
print('Method 1: ' + str(t.timeit(100))) 
t = timeit.Timer(method2, setup) 
print('Method 2: ' + str(t.timeit(100))) 

Résultats:

 
Method 1: 1.25699996948 
Method 2: 1.46600008011 

Si vous devez parcourir une liste, utilisez un for.

+0

Une petite addition: En python-3.x, le test de performance montrera que la carte ne prend qu'une fraction de milliseconde. C'est parce qu'il retournera un itérateur. method2 = 'list (map (itemgetter (1), elements))' rend l'ancien comportement. –

+0

Ceci devrait être la réponse acceptée. –

21

Cela fonctionne aussi:

zip(*elements)[1] 

(je signale surtout cela, pour me prouver que je groked zip ...)

Voir en action:

>>> help(zip) 

Aide sur la fonction zip intégrée dans le module intégré:

zip (...)

zip (SEQ1 [, seq2 [...]]) -> [(SEQ1 [0], seq2 [0] ...) (...) ]

Retourne une liste de tuples, où chaque ligne contient le ième élément de chacune des séquences d'arguments. La liste renvoyée est tronquée à la longueur de la séquence d'arguments la plus courte.

>>> elements = [(1,1,1),(2,3,7),(3,5,10)] 
>>> zip(*elements) 
[(1, 2, 3), (1, 3, 5), (1, 7, 10)] 
>>> zip(*elements)[1] 
(1, 3, 5) 
>>> 

chose Neat j'ai appris aujourd'hui: Utilisez *list dans les arguments pour créer une liste de paramètres pour une fonction ...

+2

et utilisez '** dict' pour créer des arguments de mots-clés:' def test (foo = 3, bar = 3): retourne foo * bar' puis 'd = {'bar': 9, 'foo' = 12}; test d'impression (** d) ' –

+0

@Wayne Werner: Oui. Ce truc n'était que de la connaissance passive (je ne m'en sers pas souvent) - mais il est bon de se rappeler maintenant et alors de savoir où/quoi chercher ... –

+0

Histoire vraie - Je trouve cela dans tout ce que j'utilise souvent assez (Python, vim), j'ai tendance à avoir besoin de rappels de fonctionnalités soignées/cool que j'ai oubliées car je ne les utilise pas * souvent *. –

9

à cet que je cherchais dans quel sens est le plus rapide pour tirer le deuxième élément d'une liste de 2-tuple.Pas ce que je voulais, mais couru même test comme le montre avec une 3ème méthode, plus tester la méthode zip

setup = 'elements = [(1,1) for _ in range(100000)];from operator import itemgetter' 
method1 = '[x[1] for x in elements]' 
method2 = 'map(itemgetter(1), elements)' 
method3 = 'dict(elements).values()' 
method4 = 'zip(*elements)[1]' 

import timeit 
t = timeit.Timer(method1, setup) 
print('Method 1: ' + str(t.timeit(100))) 
t = timeit.Timer(method2, setup) 
print('Method 2: ' + str(t.timeit(100))) 
t = timeit.Timer(method3, setup) 
print('Method 3: ' + str(t.timeit(100))) 
t = timeit.Timer(method4, setup) 
print('Method 4: ' + str(t.timeit(100))) 

Method 1: 0.618785858154 
Method 2: 0.711684942245 
Method 3: 0.298138141632 
Method 4: 1.32586884499 

donc deux fois plus rapide si vous avez une paire de 2 tuple juste convertir en un dict et prendre les valeurs.

+0

Ceci est probablement évident mais je mentionnerais 'dict (elements) .values ​​() 'aboutira à une dictée à un élément par opposition à une liste de comprahension ou une carte. C'est exactement ce que je voulais (je m'intéressais aux touplets uniques) (+1 et merci beaucoup pour poster) mais d'autres pourraient se demander pourquoi dict est plus rapide - il n'alloue pas de mémoire mais seulement vérifie l'élément existant. – Greg0ry

2
map (lambda x:(x[1]),elements) 
+4

Pensez à ajouter quelques explications. – fedorqui

0

minutage pour python 3,6 pour extraire le second élément dans une liste 2-tuple.

De plus, ajouté numpy méthode de tableau, qui est plus simple à lire (mais sans doute plus simple que la compréhension de la liste).

from operator import itemgetter 
elements = [(1,1) for _ in range(100000)] 

%timeit second = [x[1] for x in elements] 
%timeit second = list(map(itemgetter(1), elements)) 
%timeit second = dict(elements).values() 
%timeit second = list(zip(*elements))[1] 
%timeit second = np.array(elements)[:,1] 

et les horaires:

list comprehension: 4.73 ms ± 206 µs per loop 
list(map):   5.3 ms ± 167 µs per loop 
dict:    2.25 ms ± 103 µs per loop 
list(zip)   5.2 ms ± 252 µs per loop 
numpy array:  28.7 ms ± 1.88 ms per loop 

Notez que map() et zip() ne reviennent pas une liste plus, d'où la conversion explicite.