web-dev-qa-db-fra.com

Comment extraire les n-èmes éléments d'une liste de tuples?

J'essaie d'obtenir les n-ième éléments d'une liste de n-uplets.

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 être fait avec une boucle for mais je voulais savoir s'il y avait un autre moyen puisque j'ai des milliers de n-uplets.

79
pleasedontbelong
[x[1] for x in elements]
148
luc

Je sais que cela pourrait être fait avec un FOR mais je voulais savoir s'il y avait un autre moyen 

Il y a un autre moyen. Vous pouvez aussi le faire avec map et itemgetter :

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

Ceci effectue toujours une boucle en interne et 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:

 Méthode 1: 1.25699996948 
 Méthode 2: 1.46600008011 

Si vous avez besoin de parcourir une liste, utilisez for, c'est bien.

26
Mark Byers

Cela fonctionne aussi:

Zip(*elements)[1]

(Je publie principalement ceci, pour me prouver que j’ai grillé Zip...)

Voyez-le en action:

>>> help(Zip)

Aide sur la fonction intégrée Zip in module builtin :

Zip *: français(...)

Zip (seq1 [ seq2 [...]]) -> [(seq1 [0], seq2 [0] ...), (...)]

Retourne une liste de tuples, où chaque Tuple contient le i-ème élément de chacune des séquences d'arguments. La liste renvoyée est tronquée de longueur à 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 intéressante que j'ai apprise aujourd'hui: utilisez *list dans les arguments pour créer une liste de paramètres pour une fonction ...

Note: En Python3, Zip renvoie un itérateur. Utilisez donc list(Zip(*elements)) pour renvoyer une liste de n-uplets.

24
Daren Thomas

J'ai trouvé cela, alors que je cherchais quelle voie est la plus rapide pour extraire le deuxième élément d'une liste à 2 tuples. Pas ce que je voulais, mais j'ai exécuté le même test que celui indiqué avec une troisième méthode, ainsi que 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 vite si vous avez une paire de 2 Tuple à convertir simplement en dict et prenez les valeurs.

11
Graeme Gellatly
map (lambda x:(x[1]),elements)
3
Thras

Timings for Python 3.6 pour extraire le deuxième élément d'une liste de 2 Tuple. 

Ajoutons également la méthode de tableau numpy, qui est plus simple à lire (mais 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 renvoient plus de liste, d’où la conversion explicite.

2
Oleg

Utilisation de islice et chain.from_iterable :

>>> from itertools import chain, islice
>>> elements = [(1,1,1),(2,3,7),(3,5,10)]
>>> list(chain.from_iterable(islice(item, 1, 2) for item in elements))
[1, 3, 5]

Cela peut être utile lorsque vous avez besoin de plus d'un élément:

>>> elements = [(0, 1, 2, 3, 4, 5), 
                (10, 11, 12, 13, 14, 15), 
                (20, 21, 22, 23, 24, 25)]
>>> list(chain.from_iterable(islice(Tuple_, 2, 5) for Tuple_ in elements))
[2, 3, 4, 12, 13, 14, 22, 23, 24]
1
Georgy