2010-07-22 6 views
61

Ich versuche, die n-ten Elemente aus einer Liste von Tupeln zu erhalten.Wie extrahiert man die n-ten Elemente aus einer Liste von Tupeln in Python?

Ich habe so etwas wie:

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

ich nur die zweiten Elemente jedes Tupel in eine Liste extrahieren mag:

seconds = [1, 3, 5] 

Ich weiß, dass es mit einer for Schleife getan werden könnte, aber Ich wollte wissen, ob es einen anderen Weg gibt, da ich tausende Tupel habe.

Antwort

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

Ich weiß, dass es mit einer FOR getan werden könnte, aber ich wollte wissen, ob es eine andere Möglichkeit ist

Es gibt einen anderen Weg. Sie können es auch tun, mit map und itemgetter:

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

Dies führt noch eine Schleife intern obwohl, und es ist etwas langsamer als die Liste Verständnis:

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

Ergebnisse:

 
Method 1: 1.25699996948 
Method 2: 1.46600008011 

Wenn Sie über eine Liste iterieren müssen, dann ist die Verwendung einer for in Ordnung.

+0

Eine kleine Ergänzung: In Python-3.x zeigt der Benchmark, dass die Karte nur einen Bruchteil einer Millisekunde dauert. Das ist, weil es einen Iterator zurückgibt. method2 = 'list (map (itemgetter (1), elements))' gibt das alte Verhalten wieder. –

+0

Dies sollte die akzeptierte Antwort sein. –

21

Dies funktioniert auch:

zip(*elements)[1] 

(ich hauptsächlich das bin Entsendung, um mir zu beweisen, dass ich groked haben zip ...)

Sehen sie in Aktion:

>>> help(zip) 

Hilfe zur integrierten Funktion zip in Modul eingebaut:

zip (...)

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

Gibt eine Liste von Tupeln zurück, wobei jedes Tupel das i-te Element von jeder der Argumentsequenzen enthält. Die zurückgegebene Liste wird Länge auf die Länge der kürzesten Argumentsequenz abgeschnitten.

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

Ordentlich, was ich heute gelernt: Verwenden Sie *list in Argumenten eine Parameterliste für eine Funktion erstellen ...

+2

und benutze '** dict', um Schlüsselwortargumente zu erzeugen:' def test (foo = 3, bar = 3): gib foo * bar' zurück, dann 'd = {'bar': 9, 'foo' = 12}; Druckprobe (** d) ' –

+0

@Wayne Werner: Ja. Dieses Zeug war alles nur passives Wissen (ich benutze es nicht oft) - aber es ist gut daran erinnert zu werden und dann weißt du wo/was du suchen musst ... –

+0

Wahre Geschichte - das finde ich in allem was ich oft benutze Genug (Python, vim), ich brauche eher Erinnerungen an ordentliche/coole Features, die ich vergessen habe, weil ich sie nicht oft * benutze. –

9

diese gefunden, als ich für die Art und Weise war auf der Suche ist am schnellsten das zweite Element zu ziehen einer 2-Tupel-Liste.Nicht das, was ich wollte, aber lief gleichen Test wie mit einem dritten Verfahren und testen Sie die Zip-Methode

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 

Also mehr als doppelt so schnell, wenn Sie einen 2 Tupelpaar haben gezeigt, nur auf einen dict zu konvertieren und die Werte zu nehmen.

+0

Dies ist wahrscheinlich offensichtlich, aber ich würde 'dict (elements) .values ​​() erwähnen 'führt im Gegensatz zur Listenkomprehension oder -karte zu einem Element-Diktat. Genau das wollte ich (ich war an Unique Touples interessiert) (+1 und vielen Dank für das Posting), aber andere fragen sich vielleicht, warum dict schneller ist - es reserviert nicht nur Speicher, sondern prüft nur gegen existierende Elemente. – Greg0ry

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

Erwägen Sie, einige Erklärungen hinzuzufügen. – fedorqui

0

Timings für Python 3.6 für aus einer 2-Tupel-Liste, um das zweite Element zu extrahieren.

Auch hinzugefügt numpy Array-Methode, die einfacher zu lesen ist (aber wohl einfacher als das Listenverständnis).

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] 

und die Timings:

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 

Beachten Sie, dass map() und zip() keine Liste zurück mehr, daher die explizite Konvertierung.

Verwandte Themen