Ich frage mich, ob es eine Abkürzung gibt, um eine einfache Liste aus einer Liste von Listen in Python zu erstellen.
Ich kann das in einer "for"-Schleife machen, aber vielleicht gibt es einen coolen "Einzeiler"? Ich habe es mit reduce()
versucht, aber ich bekomme einen Fehler.
Code
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
reduce(lambda x, y: x.extend(y), l)
Fehlermeldung
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
AttributeError: 'NoneType' object has no attribute 'extend'
Gegeben eine Liste von Listen l
,
flat_list = [item for sublist in l for item in sublist]`
was bedeutet:
flat_list = []
for sublist in l:
for item in sublist:
flat_list.append(item)
ist schneller als die bisher veröffentlichten Abkürzungen. (l
ist die zu glättende Liste.)
Hier ist die entsprechende Funktion:
flatten = lambda l: [item for sublist in l for item in sublist]
Als Beweis können Sie das Modul timeit
in der Standardbibliothek verwenden:
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in l for item in sublist]'
10000 loops, best of 3: 143 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 969 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,l)'
1000 loops, best of 3: 1.1 msec per loop
Erklärung: die auf +
basierenden Abkürzungen (einschließlich der impliziten Verwendung in sum
) sind notwendigerweise O(L**2)
, wenn es L Unterlisten gibt -- da die Zwischenergebnisliste immer länger wird, wird bei jedem Schritt ein neues Zwischenergebnislisten-Objekt zugewiesen, und alle Elemente des vorherigen Zwischenergebnisses müssen rüberkopiert werden (sowie einige neue am Ende hinzugefügt werden). Der Einfachheit halber und ohne Verlust der Allgemeingültigkeit sei angenommen, dass Sie L Unterlisten mit jeweils I Elementen haben: die ersten I Elemente werden L-1 mal hin- und herkopiert, die zweiten I Elemente L-2 mal, und so weiter; die Gesamtzahl der Kopien ist I mal die Summe von x für x von 1 bis L ausgeschlossen, d.h. I * (L**2)/2
.
Das Listenverständnis erzeugt nur einmal eine Liste und kopiert jedes Element (von seinem ursprünglichen Aufenthaltsort in die Ergebnisliste) ebenfalls genau einmal.
Anmerkung des Autors: Das ist ineffizient. Aber es macht Spaß, weil monoids großartig ist. Es ist nicht geeignet für die Produktion Python-Code.
>>> sum(l, [])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Dies summiert einfach die Elemente der im ersten Argument übergebenen iterable, wobei das zweite Argument als Anfangswert der Summe behandelt wird (wenn es nicht angegeben wird, wird stattdessen 0
verwendet und in diesem Fall wird ein Fehler ausgegeben).
Da Sie verschachtelte Listen summieren, erhalten Sie tatsächlich [1,3]+[2,4]
als Ergebnis von sum([[1,3],[2,4]],[])
, was gleich [1,3,2,4]
ist.
Beachten Sie, dass dies nur bei Listen von Listen funktioniert. Für Listen von Listen von Listen brauchen Sie eine andere Lösung.
from functools import reduce #python 3
>>> l = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(lambda x,y: x+y,l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Die Methode extend()
in Ihrem Beispiel verändert x
, anstatt einen nützlichen Wert zurückzugeben (den reduce()
erwartet).
Ein schnellerer Weg, die reduce
Version zu machen, wäre
>>> import operator
>>> l = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(operator.concat, l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]