Ich habe eine Liste mit Tupeln mit zwei Elementen und möchte sie in zwei Listen konvertieren, wobei das erste das erste Element in jedem Tupel enthält 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 macht?
Antworten:
zip
ist seine eigene Umkehrung! Vorausgesetzt, Sie verwenden den speziellen * -Operator.Dies funktioniert durch Aufrufen
zip
mit den folgenden Argumenten:… Außer dass die Argumente
zip
direkt an übergeben werden (nachdem sie in ein Tupel konvertiert wurden), sodass Sie sich keine Sorgen machen müssen, dass die Anzahl der Argumente zu groß wird.quelle
zip([], [])
diese Weise bringt Sie nicht[], []
. Es bringt dich[]
. Wenn nur ...zip
funktioniert in Python 3 genauso, außer dass ein Iterator anstelle einer Liste zurückgegeben wird. Um die gleiche Ausgabe wie oben zu erhalten, müssen Sie nur den Zip-Aufruf in eine Listelist(zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)]))
[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
list
s sind in Ordnung. Aber wenn Sie versuchen , das vollständige Ergebnis zu realisieren alle auf einmal (durchlist
das Ergebnis der ifyingzip
), könnten Sie viel Speicher verwenden (weil alle dietuple
s muss auf einmal erstellt werden). Wenn Sie das Ergebniszip
nurlist
durchlaufen können, ohne zu zögern, sparen Sie viel Speicher. Das einzige andere Problem ist, ob die Eingabe viele Elemente enthält. Die Kosten dort sind, dass sie alle als Argumente entpackenzip
müssen und Iteratoren für alle von ihnen erstellen und speichern müssen. Dies ist nur bei sehr langenlist
s ein echtes Problem (denken Sie an Hunderttausende von Elementen oder mehr).Sie könnten auch tun
Es sollte besser skalieren. Vor allem, wenn Python es gut macht, das Listenverständnis nicht zu erweitern, es sei denn, dies wird benötigt.
(Im Übrigen wird ein 2-Tupel (Paar) von Listen erstellt, anstatt wie hier eine Liste von Tupeln
zip
.)Wenn Generatoren anstelle von tatsächlichen Listen in Ordnung sind, würde dies Folgendes bewirken:
Die Generatoren durchsuchen die Liste erst, wenn Sie nach jedem Element fragen. Andererseits behalten sie Verweise auf die ursprüngliche Liste bei.
quelle
zip(*x)
Version.zip(*x)
erfordert nur einen Durchgang durch die Schleife und verbraucht keine Stapelelemente.zip
wenn der Anwendungsfall darin besteht, dass die transponierten Daten sofort verwendet und verworfen werden, während die ursprünglichen Listen viel länger im Speicher bleiben.Wenn Sie Listen haben, die nicht die gleiche Länge haben, möchten Sie möglicherweise nicht die Zip-Datei gemäß der Antwort von Patricks verwenden. Das funktioniert:
Bei Listen mit unterschiedlicher Länge schneidet zip jedes Element auf die Länge der kürzesten Liste ab:
Sie können eine Karte ohne Funktion verwenden, um leere Ergebnisse mit Keine zu füllen:
zip () ist allerdings etwas schneller.
quelle
izip_longest
zip_longest
für Python3-Benutzer.Ich verwende
zip(*iterable)
(das ist der Code, den Sie suchen) gerne in meinen Programmen wie folgt:Ich finde
unzip
mehr lesbar.quelle
Gibt ein Tupel von Listen wie in der Frage.
Entpackt die beiden Listen.
quelle
Naiver Ansatz
funktioniert gut für endliche iterierbare (z. B. Sequenzen wie
list
/tuple
/str
) von (möglicherweise unendlichen) iterablen, die wie folgt dargestellt werden könnenwo
n in ℕ
,a_ij
entspricht demj
-ten Element desi
-ten iterierbaren,und nach der Bewerbung
transpose_finite_iterable
bekommen wirPython-Beispiel für einen solchen Fall
a_ij == j
, in demn == 2
Aber wir können nicht
transpose_finite_iterable
wieder verwenden, um zur Struktur des Originals zurückzukehren,iterable
daresult
es sich um eine unendliche Iteration endlicher Iterablen handelt (tuple
in unserem Fall s):Wie können wir mit diesem Fall umgehen?
... und hier kommt die
deque
Nachdem wir uns die
itertools.tee
Funktionsdokumente angesehen haben , gibt es ein Python-Rezept, das mit einigen Änderungen in unserem Fall helfen kannLass uns nachsehen
Synthese
Jetzt können wir allgemeine Funktionen für die Arbeit mit Iterablen von Iterablen definieren, von denen einige endlich und andere potenziell unendlich sind, wenn
functools.singledispatch
Dekorateure wie verwendet werdenDies kann als seine eigene Umkehrung (Mathematiker nennen diese Art von Funktionen "Involutionen" ) in der Klasse von Binäroperatoren über endliche nicht leere Iterablen betrachtet werden.
Als Bonus
singledispatch
können wir mitnumpy
Arrays wie umgehenund dann benutze es gerne
Hinweis
Da
transpose
gibt Iteratoren zurück und wenn jemand eintuple
vonlist
s wie in OP haben möchte - kann dies zusätzlich mitmap
eingebauter Funktion wie gemacht werdenWerbung
Ich habe verallgemeinerte Lösung hinzugefügt
lz
Paket aus0.5.0
Version , die verwendet werden kann , wiePS
Es gibt keine (zumindest offensichtliche) Lösung für die Behandlung von potenziell unendlich iterierbaren oder potenziell unendlich iterierbaren Elementen, aber dieser Fall ist weniger häufig.
quelle
Es ist nur ein anderer Weg, aber es hat mir sehr geholfen, also schreibe ich es hier:
Mit dieser Datenstruktur:
Ergebend:
Der pythonischere Weg, es zu entpacken und zum Original zurückzukehren, ist meiner Meinung nach dieser:
Dies gibt jedoch ein Tupel zurück. Wenn Sie also eine Liste benötigen, können Sie Folgendes verwenden:
quelle
Erwägen Sie die Verwendung von more_itertools.unzip :
quelle
Da es Tupel zurückgibt (und Tonnen von Speicher verbrauchen kann),
zip(*zipped)
scheint mir der Trick eher klug als nützlich zu sein.Hier ist eine Funktion, die Ihnen tatsächlich die Umkehrung von zip gibt.
quelle
Keine der vorherigen Antworten liefert effizient die erforderliche Ausgabe, bei der es sich eher um ein Tupel von Listen als um eine Liste von Tupeln handelt . Für die erstere können Sie
tuple
mit verwendenmap
. Hier ist der Unterschied:Darüber hinaus setzen die meisten vorherigen Lösungen Python 2.7 voraus, bei dem
zip
eine Liste anstelle eines Iterators zurückgegeben wird.Für Python 3.x müssen Sie das Ergebnis an eine Funktion wie
list
oder übergebentuple
, um den Iterator zu erschöpfen. Bei speichereffizienten Iteratoren können Sie das Äußere weglassenlist
undtuple
die entsprechenden Lösungen anfordern.quelle
Dies
zip(*seq)
ist zwar sehr nützlich, kann jedoch für sehr lange Sequenzen ungeeignet sein, da dadurch ein Tupel von Werten erstellt wird, die übergeben werden sollen. Ich habe beispielsweise mit einem Koordinatensystem mit über einer Million Einträgen gearbeitet und finde es wesentlich schneller zu erstellen die Sequenzen direkt.Ein generischer Ansatz wäre ungefähr so:
Abhängig davon, was Sie mit dem Ergebnis machen möchten, kann die Wahl der Kollektion einen großen Unterschied machen. In meinem tatsächlichen Anwendungsfall ist die Verwendung von Sets und ohne interne Schleife spürbar schneller als bei allen anderen Ansätzen.
Und wie andere angemerkt haben, kann es sinnvoll sein, stattdessen Numpy- oder Pandas-Sammlungen zu verwenden, wenn Sie dies mit Datasets tun.
quelle
Während numpy Arrays und Pandas vorzuziehen sind, ahmt diese Funktion das Verhalten nach,
zip(*args)
wenn sie als aufgerufen wirdunzip(args)
.Ermöglicht die Übergabe von Generatoren beim
args
Durchlaufen von Werten. Dekorierencls
und / odermain_cls
zur Mikroverwaltung der Containerinitialisierung.quelle