Zip mit Listenausgabe statt Tupel

94

Was ist die schnellste und eleganteste Art, eine Liste von Listen aus zwei Listen zu erstellen?

ich habe

In [1]: a=[1,2,3,4,5,6]

In [2]: b=[7,8,9,10,11,12]

In [3]: zip(a,b)
Out[3]: [(1, 7), (2, 8), (3, 9), (4, 10), (5, 11), (6, 12)]

Und ich hätte gerne

In [3]: some_method(a,b)
Out[3]: [[1, 7], [2, 8], [3, 9], [4, 10], [5, 11], [6, 12]]

Ich habe darüber nachgedacht, map anstelle von zip zu verwenden, aber ich weiß nicht, ob es eine Standardbibliotheksmethode gibt, die als erstes Argument verwendet werden kann.

Ich kann meine eigene Funktion dafür definieren und map verwenden, meine Frage ist, ob schon etwas implementiert ist. Nein ist auch eine Antwort.

Jan Vorcak
quelle
1
Brauchen Sie wirklich Listen? Was machst du mit den Ergebnissen?
Karl Knechtel
14
Ein Beispiel wäre sklearn, bei dem Daten häufig auf diese Weise organisiert werden müssen.
tumultous_rooster

Antworten:

101

Wenn Sie mehr als 2 Listen (oder sogar nur 2) komprimieren, ist ein lesbarer Weg:

[list(a) for a in zip([1,2,3], [4,5,6], [7,8,9])]

Dies verwendet Listenverständnisse und konvertiert jedes Element in der Liste (Tupel) in Listen.

DK
quelle
54

Sie hatten fast die Antwort selbst. Verwenden Sie nicht mapanstelle von zip. Verwenden Sie map AND zip .

Sie können die Karte zusammen mit dem Reißverschluss für einen eleganten, funktionalen Ansatz verwenden:

list(map(list, zip(a, b)))

zipGibt eine Liste von Tupeln zurück. map(list, [...])ruft listjedes Tupel in der Liste auf. list(map([...])verwandelt das Kartenobjekt in eine lesbare Liste.

Eldamir
quelle
Die unglückliche Entscheidung, Python 3-Sammlungsoperationen zurückzubringen, führt hier zu generatorden Kosten des Doppelten list.
Javadba
15

Ich mag die Eleganz der Zip-Funktion, aber die Verwendung der itemgetter () -Funktion im Bedienermodul scheint viel schneller zu sein. Ich habe ein einfaches Skript geschrieben, um dies zu testen:

import time
from operator import itemgetter

list1 = list()
list2 = list()
origlist = list()
for i in range (1,5000000):
        t = (i, 2*i)
        origlist.append(t)

print "Using zip"
starttime = time.time()
list1, list2 = map(list, zip(*origlist))
elapsed = time.time()-starttime
print elapsed

print "Using itemgetter"
starttime = time.time()
list1 = map(itemgetter(0),origlist)
list2 = map(itemgetter(1),origlist)
elapsed = time.time()-starttime
print elapsed

Ich habe erwartet, dass Zip schneller sein wird, aber die Itemgetter-Methode gewinnt bei weitem:

Using zip
6.1550450325
Using itemgetter
0.768098831177
kslnet
quelle
2
Dies ist eine Umsetzung dessen, was das OP zu tun versucht. Könnten Sie Ihren Beitrag aktualisieren, um dies widerzuspiegeln? Das heißt, OP konvertiert zwei Listen in eine Liste oder eine beliebige Anzahl von Paaren. Sie konvertieren eine beliebige Anzahl von Paaren in ein Listenpaar.
Mad Physicist
Mit welcher Python-Version wird das gemessen?
Moberg
Ich erinnere mich nicht, es war vor über zwei Jahren, aber höchstwahrscheinlich 2.6 oder 2.7. Ich kann mir vorstellen, dass Sie den Code kopieren und auf Ihrer eigenen Version / Plattform ausprobieren können.
kslnet
2
Python 2 ziperstellt eine echte Liste. Das verlangsamt die Dinge. Versuchen Sie es zipmit itertools.izip.
Jean-François Fabre
In Python 3.5 dauert das Zip 3,5 Sekunden und der Itemgetter 0,10 Sekunden. Für diejenigen, die Listenverständnis lieben, list1 = [x[0] for x in origlist]funktioniert es genauso gut wie list1 = map(itemgetter(0), origlist).
Elias Strehle
3

Ich mag Lambda im Allgemeinen nicht, aber ...

>>> a = [1, 2, 3, 4, 5]
>>> b = [6, 7, 8, 9, 10]
>>> c = lambda a, b: [list(c) for c in zip(a, b)]
>>> c(a, b)
[[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]]

Wenn Sie die zusätzliche Geschwindigkeit benötigen, ist die Karte etwas schneller:

>>> d = lambda a, b: map(list, zip(a, b))
>>> d(a, b)
[[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]]

Die Karte gilt jedoch als unpythonisch und sollte nur zur Leistungsoptimierung verwendet werden.

Ceasar Bautista
quelle
4
Was lambdafügt hier hinzu? Man kann den Ausdruck einfach schreiben, anstatt eine Funktion aufzurufen (es ist wirklich nicht kompliziert), und selbst wenn man eine Funktion dafür möchte, kann sie schmerzlos in zwei Zeilen definiert werden (eine, wenn Ihre Eingabetaste kaputt ist oder Sie verrückt sind). . mapAuf der anderen Seite ist es vollkommen in Ordnung, wenn das erste Argument eine einfache Funktion wäre (im Gegensatz zu a lambda).
1
Nun, er bat um eine Funktion. Aber ich stimme zu - wahrscheinlich besser, nur um die zusätzliche Leitung zu bezahlen. Was die Karte betrifft, glaube ich, dass das Listenverständnis fast immer klarer ist.
Ceasar Bautista
1
Ich würde mapüber empfehlen lambda. so map(list, zip(a,b)). Das Listenverständnis mag etwas klarer sein, aber die Karte sollte schneller sein (ungetestet)
inspectorG4dget
Ich meine, wenn das OP Geschwindigkeit braucht, ist die Karte der richtige Weg. Im Allgemeinen und insbesondere in Python sollten Sie jedoch die Lesbarkeit über die Geschwindigkeit legen (andernfalls tauchen Sie in eine vorzeitige Optimierung ein).
Ceasar Bautista
3

Wie wäre es damit?

>>> def list_(*args): return list(args)

>>> map(list_, range(5), range(9,4,-1))
[[0, 9], [1, 8], [2, 7], [3, 6], [4, 5]]

Oder noch besser:

>>> def zip_(*args): return map(list_, *args)
>>> zip_(range(5), range(9,4,-1))
[[0, 9], [1, 8], [2, 7], [3, 6], [4, 5]]
Broseph
quelle
Das scheint mir eine bessere Antwort zu sein als der Rest, da wir hier einen Schritt reduzieren, indem wir keinen Reißverschluss machen und direkt eine Liste erstellen. Genial
Akshay Hazari
2

Mit numpy

Die Definition von Eleganz kann durchaus fraglich sein, aber wenn Sie mit numpyder Erstellung eines Arrays und seiner Konvertierung in eine Liste arbeiten (falls erforderlich ...), kann dies sehr praktisch sein, auch wenn es im Vergleich zur mapFunktion oder zum Listenverständnis nicht so effizient ist .

import numpy as np 
a = b = range(10)
zipped = zip(a,b)
result = np.array(zipped).tolist()
Out: [[0, 0],
 [1, 1],
 [2, 2],
 [3, 3],
 [4, 4],
 [5, 5],
 [6, 6],
 [7, 7],
 [8, 8],
 [9, 9]]

Andernfalls überspringen Sie die zipFunktion, die Sie direkt verwenden können np.dstack:

np.dstack((a,b))[0].tolist()
GM
quelle
1

Listenverständnis wäre eine sehr einfache Lösung, denke ich.

a=[1,2,3,4,5,6]

b=[7,8,9,10,11,12]

x = [[i, j] for i, j in zip(a,b)]

print(x)

output : [[1, 7], [2, 8], [3, 9], [4, 10], [5, 11], [6, 12]]
axai_m
quelle