Come estrarre gli elementi n-esimi da un elenco di tuple?


112

Sto cercando di ottenere gli elementi n-esimi da un elenco di tuple.

Ho qualcosa come:

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

Desidero estrarre solo i secondi elementi di ogni tupla in una lista:

seconds = [1, 3, 5]

So che potrebbe essere fatto con un forciclo, ma volevo sapere se esiste un altro modo poiché ho migliaia di tuple.

Risposte:


185
n = 1 # N. . .
[x[n] for x in elements]

34

Funziona anche:

zip(*elements)[1]

(Sto principalmente postando questo, per dimostrare a me stesso che ho groked zip...)

Guardalo in azione:

>>> help(zip)

Guida in funzione built-zip nel modulo incorporato :

cerniera lampo(...)

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

Restituisce un elenco di tuple, in cui ogni tupla contiene l'elemento i-esimo di ciascuna delle sequenze di argomenti. L'elenco restituito viene troncato in lunghezza alla lunghezza della sequenza di argomenti più breve.

>>> 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)
>>>

Cosa carina che ho imparato oggi: utilizzare *listnegli argomenti per creare un elenco di parametri per una funzione ...

Nota : in Python3, ziprestituisce un iteratore, quindi usa invece list(zip(*elements))per restituire un elenco di tuple.


2
e utilizzare **dictper creare argomenti di parole chiave: def test(foo=3, bar=3): return foo*barquindid = {'bar': 9, 'foo'=12}; print test(**d)
Wayne Werner

@ Wayne Werner: Sì. Questa roba era solo conoscenza passiva (non la uso spesso) - ma è bene che mi venga ricordata di tanto in tanto in modo da sapere dove / cosa cercare ...
Daren Thomas,

1
Storia vera - trovo che in qualsiasi cosa io uso abbastanza spesso (Python, vim), tendo a ricordi bisogno di pulito / freddo caratteristiche che ho dimenticato perché io non li uso che spesso.
Wayne Werner,

la sintassi * list è piuttosto utile. qualche idea su dove sia descritto nella documentazione ufficiale di Python?
user1748155

L'ho trovato solo nel tutorial: docs.python.org/2/tutorial/…
Daren Thomas,

30

So che potrebbe essere fatto con un FOR ma volevo sapere se c'è un altro modo

C'è un altro modo. Puoi farlo anche con map e itemgetter :

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

Tuttavia, questo esegue ancora un ciclo internamente ed è leggermente più lento della comprensione dell'elenco:

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)))

risultati:

Metodo 1: 1.25699996948
Metodo 2: 1.46600008011

Se è necessario iterare su un elenco, utilizzare a forva bene.


2
Una piccola aggiunta: in python-3.x il benchmark mostrerà che la mappa richiede solo una frazione di millisecondo. Questo perché restituirà un iteratore. method2 = 'list (map (itemgetter (1), elements))' rende il vecchio comportamento.
Maik Beckmann

12

L'ho trovato mentre cercavo il modo più veloce per estrarre il secondo elemento di un elenco di 2 tuple. Non è quello che volevo, ma ho eseguito lo stesso test mostrato con un terzo metodo oltre a testare il metodo 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

Quindi più del doppio della velocità se hai una coppia di 2 tuple da convertire in un dict e prendere i valori.


Questo è probabilmente ovvio, ma vorrei menzionare che dict(elements).values()si tradurrà in un dict a un elemento anziché in list comprahension o map. Questo è esattamente quello che volevo (ero interessato a touples unici) (+1 e un grande grazie per la pubblicazione) ma altri potrebbero chiedersi perché dict è più veloce: non alloca memoria ma controlla solo l'elemento esistente.
Greg0ry

6

Tempistiche per Python 3.6 per l'estrazione del secondo elemento da un elenco di 2 tuple.

Inoltre, aggiunto il numpymetodo degli array, che è più semplice da leggere (ma probabilmente più semplice della comprensione dell'elenco).

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]

e le tempistiche:

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

Nota che map()e zip()non restituisce più un elenco, da qui la conversione esplicita.



1

Utilizzando islicee 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]

Questo può essere utile quando hai bisogno di più di un elemento:

>>> 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]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.