Verwenden Sie das Listenverständnis, um ein Tupel zu erstellen

70

Wie kann ich das Listenverständnis verwenden, um aus einer Liste ein Tupel mit 2 Tupeln zu erstellen? Es wäre gleichbedeutend mit

tup = ()
for element in alist:
    tup = tup + ((element.foo, element.bar),)
Lim H.
quelle

Antworten:

99
tup = tuple((element.foo, element.bar) for element in alist)

Technisch gesehen ist es ein Generatorausdruck . Es ist wie ein Listenverständnis, wird jedoch träge ausgewertet und muss keinen Speicher für eine Zwischenliste zuweisen.

Der Vollständigkeit halber würde das Listenverständnis folgendermaßen aussehen:

tup = tuple([(element.foo, element.bar) for element in alist])

 

PS: attrgetterist nicht schneller ( alisthat eine Million Artikel hier):

In [37]: %timeit tuple([(element.foo, element.bar) for element in alist])
1 loops, best of 3: 165 ms per loop

In [38]: %timeit tuple((element.foo, element.bar) for element in alist)
10 loops, best of 3: 155 ms per loop

In [39]: %timeit tuple(map(operator.attrgetter('foo','bar'), alist))
1 loops, best of 3: 283 ms per loop

In [40]: getter = operator.attrgetter('foo','bar')

In [41]: %timeit tuple(map(getter, alist))
1 loops, best of 3: 284 ms per loop

In [46]: %timeit tuple(imap(getter, alist))
1 loops, best of 3: 264 ms per loop
Pavel Anossov
quelle
1
(+1) Könnte erwähnenswert sein, dass dies technisch gesehen kein Listenverständnis ist (aber ich bin sicher, dass das OP nichts dagegen hat :))
NPE
3
du könntest es auch tun tuple(map(operator.attrgetter('foo','bar'),alist)). Ich würde wahrscheinlich die von Ihnen veröffentlichte zur besseren Lesbarkeit verwenden, attrgetterkönnte aber einen leichten Leistungsvorteil haben. Sie müssten timeitund sehen, ob dies in einer wirklich engen Schleife ist.
mgilson
2
Was ist der Unterschied zwischen einem Listenverständnis und einem Generatorausdruck in diesem Beispiel, da tuple () darauf aufgerufen wird? Würde es nicht unabhängig von der Form den gleichen Speicherbedarf beanspruchen?
Octipi
1
Das Übergeben des Generatorausdrucks an den Tupelkonstruktor bewirkt die Auswertung des gesamten Generatorausdrucks und verwendet denselben Speicher wie das Listenverständnis. Das Listenverständnis läuft auf meinem Computer etwa 20% schneller. Ich kann den Vorteil eines Generators erkennen, wenn ich die Begriffe einzeln verwende, sehe aber keinen Vorteil, wenn ich an den Tupelkonstruktor übergebe.
Octipi
2
@EricRoper Nein, es wird das Doppelte des Speichers verwendet. Zuerst werden alle Elemente des Generators zum Erstellen einer Liste verwendet, und dann wird aus der Liste ein Tupel erstellt. Zu diesem Zeitpunkt gibt es zwei Kopien der "Menge" von Elementen, die vom Generator ausgegeben werden, und erst nach einiger Zeit wird die Liste mit Müll gesammelt. Wenn der Generator sehr groß ist, können Sie möglicherweise nicht gleichzeitig die Liste und das Tupel im Speicher behalten, selbst für eine Anweisung. Die Verlangsamung von attrgetter wird erwartet, da Sie eine Attributsuche durch einen Funktionsaufruf plus Attributsuche ersetzen.
Bakuriu
0

Sie können den folgenden Ausdruck verwenden

tup = *[(element.foo, element.bar) for element in alist]

Dies generiert zuerst eine Liste von Tupeln und konvertiert dann diese Liste von Tupeln in ein Tupel von Tupeln.

manav014
quelle