614 Stimmen

Transponieren/Entpacken-Funktion (Inverse von zip)?

Ich habe eine Liste von 2-Element-Tupeln und möchte sie in 2 Listen konvertieren, wobei die erste Liste das erste Element in jedem Tupel und die zweite Liste das zweite Element enthält.

Zum Beispiel:

original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
# and I want to become...
result = (['a', 'b', 'c', 'd'], [1, 2, 3, 4])

Gibt es eine eingebaute Funktion, die das tut?

8 Stimmen

Tolle Antworten unten, aber sehen Sie sich auch an Numpys Transponieren

5 Stimmen

Siehe diese nette Antwort, um dasselbe mit Generatoren anstelle von Listen zu tun: wie-entpacke-einen-iterator

0 Stimmen

Warum wird zip als Transponierung bezeichnet?

918voto

Patrick Punkte 86090

zip ist seine eigene Inverse! Vorausgesetzt, Sie verwenden den speziellen Operator *.

>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)])
[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]

Dies geschieht durch den Aufruf von zip mit den Argumenten:

zip(('a', 1), ('b', 2), ('c', 3), ('d', 4))

außer dass die Argumente an zip direkt (nachdem es in ein Tupel umgewandelt wurde), so dass man sich keine Sorgen machen muss, dass die Anzahl der Argumente zu groß wird.

27 Stimmen

Ach, wenn es doch nur so einfach wäre. Auspacken zip([], []) dieser Weg bringt Sie nicht weiter [], [] . Es bringt Sie [] . Wenn nur...

0 Stimmen

@user2357112 es gibt Sie zip(*zip([list1], [list2])) gibt Ihnen ([list1, list2]) .

0 Stimmen

@cdhagmann: zip([list1], [list2]) ist jedoch nie das, was Sie wollen. Das gibt Ihnen nur [(list1, list2)] .

29voto

Anders Eurenius Punkte 4125

Sie könnten auch Folgendes tun

result = ([ a for a,b in original ], [ b for a,b in original ])

Es sollte besser skalieren. Vor allem, wenn Python es schafft, die Listenkomplexe nur bei Bedarf zu erweitern.

(Nebenbei bemerkt, ergibt dies ein 2-Tupel (Paar) von Listen und nicht eine Liste von Tupeln, wie zip tut.)

Wenn Generatoren anstelle von tatsächlichen Listen in Ordnung sind, würde dies ausreichen:

result = (( a for a,b in original ), ( b for a,b in original ))

Die Generatoren fressen sich nicht durch die Liste, bis Sie nach jedem Element fragen, aber andererseits behalten sie Verweise auf die ursprüngliche Liste.

11 Stimmen

"Vor allem, wenn Python es schafft, die Listenkomplexe nur bei Bedarf zu expandieren." Hmmm... normalerweise werden Listenkomplexe sofort expandiert - oder verstehe ich da etwas falsch?

1 Stimmen

@glglgl: Nein, du hast wahrscheinlich recht. Ich hatte nur gehofft, dass eine zukünftige Version das Richtige tun würde. (Es ist nicht unmöglich, es zu ändern, die Semantik der Nebeneffekte, die geändert werden müssen, sind wahrscheinlich bereits entmutigt).

11 Stimmen

Was Sie sich erhoffen, ist ein Generatorausdruck - den es bereits gibt.

24voto

wassimans Punkte 7986

Ich verwende gerne zip(*iterable) (das ist das Stück Code, das Sie suchen) in meinen Programmen wie folgt:

def unzip(iterable):
    return zip(*iterable)

Ich finde unzip besser lesbar.

21voto

Chris Punkte 732

Wenn Sie Listen haben, die nicht gleich lang sind, sollten Sie zip nicht wie in Patricks Antwort verwenden. Das funktioniert:

>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)])
[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]

Bei Listen unterschiedlicher Länge schneidet zip jedoch jedes Element auf die Länge der kürzesten Liste ab:

>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', )])
[('a', 'b', 'c', 'd', 'e')]

Sie können map with no function verwenden, um leere Ergebnisse mit None zu füllen:

>>> map(None, *[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', )])
[('a', 'b', 'c', 'd', 'e'), (1, 2, 3, 4, None)]

zip() ist jedoch geringfügig schneller.

4 Stimmen

Sie können auch Folgendes verwenden izip_longest

4 Stimmen

Bekannt als zip_longest für python3-Benutzer.

1 Stimmen

@GrijeshChauhan Ich weiß, das ist wirklich alt, aber es ist eine seltsame eingebaute Funktion: docs.python.org/2/library/functions.html#map "Wenn function keine ist, wird die Identitätsfunktion angenommen; wenn es mehrere Argumente gibt, gibt map() eine Liste zurück, die aus Tupeln besteht, die die entsprechenden Elemente aus allen Iterablen enthalten (eine Art Transponierungsoperation). Die iterierbaren Argumente können eine Sequenz oder ein beliebiges iterierbares Objekt sein; das Ergebnis ist immer eine Liste."

19voto

Noyer282 Punkte 844
>>> original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
>>> tuple([list(tup) for tup in zip(*original)])
(['a', 'b', 'c', 'd'], [1, 2, 3, 4])

Liefert ein Tupel von Listen wie in der Frage.

list1, list2 = [list(tup) for tup in zip(*original)]

Packt die beiden Listen aus.

0 Stimmen

Ich denke, dies ist die genaueste Antwort, weil, wie die Frage fragt, es tatsächlich ein Paar von Listen (anstatt eine Liste von Tupeln) zurückgibt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X