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?

1voto

Waylon Flinn Punkte 19361

Da es Tupel zurückgibt (und eine Menge Speicher verbrauchen kann), muss die zip(*zipped) Der Trick scheint mir eher clever als nützlich zu sein.

Hier ist eine Funktion, die tatsächlich den Kehrwert von zip liefert.

def unzip(zipped):
    """Inverse of built-in zip function.
    Args:
        zipped: a list of tuples

    Returns:
        a tuple of lists

    Example:
        a = [1, 2, 3]
        b = [4, 5, 6]
        zipped = list(zip(a, b))

        assert zipped == [(1, 4), (2, 5), (3, 6)]

        unzipped = unzip(zipped)

        assert unzipped == ([1, 2, 3], [4, 5, 6])

    """

    unzipped = ()
    if len(zipped) == 0:
        return unzipped

    dim = len(zipped[0])

    for i in range(dim):
        unzipped = unzipped + ([tup[i] for tup in zipped], )

    return unzipped

0 Stimmen

Die ständige Neuerstellung von Tupeln scheint mir nicht sehr effizient zu sein, aber man könnte diesen Ansatz erweitern, indem man Deques verwendet, die Speicher im Voraus zuweisen könnten.

1voto

Charlie Clark Punkte 16276

Während zip(*seq) sehr nützlich ist, kann es für sehr lange Sequenzen ungeeignet sein, da es ein Tupel von Werten erzeugt, die übergeben werden müssen. Ich habe zum Beispiel mit einem Koordinatensystem mit über einer Million Einträgen gearbeitet und finde es wesentlich schneller, die Sequenzen direkt zu erstellen.

Ein allgemeiner Ansatz wäre etwa so:

from collections import deque
seq = ((a1, b1, …), (a2, b2, …), …)
width = len(seq[0])
output = [deque(len(seq))] * width # preallocate memory
for element in seq:
    for s, item in zip(output, element):
        s.append(item)

Aber je nachdem, was Sie mit dem Ergebnis machen wollen, kann die Wahl der Sammlung einen großen Unterschied machen. In meinem konkreten Anwendungsfall ist die Verwendung von Sets und keiner internen Schleife deutlich schneller als alle anderen Ansätze.

Und wie andere bereits angemerkt haben, könnte es sinnvoll sein, stattdessen Numpy- oder Pandas-Sammlungen zu verwenden, wenn Sie dies mit Datensätzen tun.

-1voto

mkearney Punkte 1128

Hier ist eine einfache einzeilige Antwort, die die gewünschte Ausgabe erzeugt:

original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
list(zip(*original))
# [('a', 'b', 'c', 'd'), (1, 2, 3, 4)]

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