
Dieser Artikel genau, wie Sie eine Liste von Listen (verschachtelte Liste) in Python reduzieren. Sie können itertools.chain.from_iterable(), sum() und List Comprehensions verwenden.
- Reduzieren einer Liste von Listen (2D-Liste)
- Liste mit itertools.chain.from_iterable() glätten
- Liste mit sum() glätten
- Flache Liste mit Listenverständnissen
- Geschwindigkeitsvergleich
- Reduzieren Sie 3D- und mehr multidimensionale Listen und unregelmäßige Listen
Verwenden Sie ravel() oder flatten(), um ein NumPy-Array ndarray zu glätten.
Im Gegenteil, lesen Sie den following Artikel darüber, wie Sie ein eindimensionales ndarray oder eine Liste in zwei Dimensionen konvertieren.
Reduzieren einer Liste von Listen (2D-Liste)
Liste mit itertools.chain.from_iterable() glätten
Sie können eine Liste von Listen mit itertools.chain.from_iterable() glätten.
import itertools
l_2d = [[0, 1], [2, 3]]
print(list(itertools.chain.from_iterable(l_2d)))
# [0, 1, 2, 3]
itertools.chain.from_iterable() gibt einen Iterator zurück, wenn Sie ihn auch in eine Liste konvertieren möchten, verwenden Sie list(). Es ist nicht erforderlich, eine Liste zu erstellen, wenn es in einer for-Anweisung verwendet wird.
Ein Tupel von Tupeln kann auf dieselbe Weise behandelt werden. Im following Beispiel WIRD das Ergebnis mit tuple() in ein Tupel umgewandelt. Wenn SIE Eine Liste benötigen, verwenden SIE list().
t_2d = ((0, 1), (2, 3))
print(tuple(itertools.chain.from_iterable(t_2d)))
# (0, 1, 2, 3)
Nur 2D-Listen können mit itertools.chain.from_iterable() abgeflacht werden. Beim 3D- oder mehrdimensionalen Hören sieht das Ergebnis wie folgt aus.
l_3d = [[[0, 1], [2, 3]], [[4, 5], [6, 7]]]
print(list(itertools.chain.from_iterable(l_3d)))
# [[0, 1], [2, 3], [4, 5], [6, 7]]
Ein Fehler wird ausgelöst, wenn er nicht iterierbare Objekte wie int oder float enthält.
l_mix = [[0, 1], [2, 3], 4]
# print(list(itertools.chain.from_iterable(l_mix)))
# TypeError: 'int' object is not iterable
Fälle mit mehrdimensionalen 3D- oder mehrdimensionalen Listen und unregelmäßigen Listen werden später beschrieben.
Liste mit sum() glätten
Sie können eine Liste von Listen auch mit der eingebauten Funktion sum() glätten.
Als zweites Argument von sum() kann ein Anfangswert angegeben werden. Wenn Sie die leere Liste [] übergeben, wird die +-Operation der Liste Listen verketten.
Beachten Sie, dass der Standardwert des zweiten Arguments 0 ist. If es also weggelassen WIRD, WIRD EIN Fehler aufgrund der Operation + mit int und list ausgelöst.
print(sum(l_2d, []))
# [0, 1, 2, 3]
# print(sum(l_2d))
# TypeError: unsupported operand type(s) for +: 'int' and 'list'
Tupel können auf dieselbe Weise behandelt werden.
print(sum(t_2d, ()))
# (0, 1, 2, 3)
Wie itertools.chain.from_iterable() funktioniert es nicht für mehr als 3D oder unregelmäßige Listen.
print(sum(l_3d, []))
# [[0, 1], [2, 3], [4, 5], [6, 7]]
# print(sum(l_mix, []))
# TypeError: can only concatenate list (not "int") to list
Flache Liste mit Listenverständnissen
Sie können auch eine Liste von Listen mit verschachtelten Listenverständnissen reduzieren.
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [x for row in matrix for x in row]
print(flat)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
Das obige Beispiel entspricht der following verschachtelten for-Schleife.
flat = []
for row in matrix:
for x in row:
flat.append(x)
print(flat)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
Im Fall des obigen Listenverständnisses kann wie bei den anderen Methoden nur eine Ebene abgeflacht werden, und es wird ein Fehler ausgelöst, wenn nicht iterierbare Objekte enthalten sind.
Es ist auch möglich, die Verschachtelung tiefer zu machen, um mehr als drei Dimensionen zu unterstützen, oder abhängig vom Typ des Elements eine bedingte Verzweigung vorzunehmen, aber dies wird nicht empfohlen, da es zu kompliziert wäre.
Weitere Informationen zu Hörverständnissen finden Sie im following Artikel.
Geschwindigkeitsvergleich
Beachten Sie, dass sum() zwar einfach zu verwenden, aber viel langsamer ist als itertools.chain.from_iterable() oder list comprehensions, wenn die Anzahl der Zeilen (die Anzahl der inneren Listen) groß ist. Es ist besser, sum() nicht zu verwenden, wenn die Anzahl der Zeilen groß ist und Verarbeitungsgeschwindigkeit und Speichereffizienz wichtig sind.
Obwohl Sie itertools importieren müssen, ist itertools.chain.from_iterable() schneller als die Listenverständnisse.
Der folgende Befehlscode wird mit dem magischen %%timeit auf Jupyter Notebook gemessen. Beachten Sie, dass es mit Python-Skript nicht funktioniert.
5 Zeilen:
l_2d_5 = [[0, 1, 2] for i in range(5)]
print(l_2d_5)
# [[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]
%%timeit
list(itertools.chain.from_iterable(l_2d_5))
# 537 ns ± 4.59 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%%timeit
sum(l_2d_5, [])
# 319 ns ± 1.85 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%%timeit
[x for row in l_2d_5 for x in row]
# 764 ns ± 32.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
100 Zeilen:
l_2d_100 = [[0, 1, 2] for i in range(100)]
%%timeit
list(itertools.chain.from_iterable(l_2d_100))
# 6.94 µs ± 139 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%%timeit
sum(l_2d_100, [])
# 35.5 µs ± 1.2 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%%timeit
[x for row in l_2d_100 for x in row]
# 13.5 µs ± 959 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
10000 Zeilen:
l_2d_10000 = [[0, 1, 2] for i in range(10000)]
%%timeit
list(itertools.chain.from_iterable(l_2d_10000))
# 552 µs ± 79.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%%timeit
sum(l_2d_10000, [])
# 343 ms ± 2.19 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
[x for row in l_2d_10000 for x in row]
# 1.11 ms ± 110 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Reduzieren Sie 3D- und mehr multidimensionale Listen und unregelmäßige Listen
Es ist notwendig, eine neue Funktion zu definieren, um 3D- und mehrdimensionale Listen oder unregelmäßige Listen zu glätten.
Der following Beispielcode basiert auf dem following Artikel.
import collections
def flatten(l):
for el in l:
if isinstance(el, collections.abc.Iterable) and not isinstance(el, (str, bytes)):
yield from flatten(el)
else:
yield el
Der Typ des Elements wird von isinstance() geprüft und rekursiv verarbeitet.
Bestimmen Sie Sie mit collections.abc.Iterable, ob el iterierbar ist. Sie müssen die Standardbibliothekssammlungen importieren.
Der String str und der Byte-String bytes sind ebenfalls iterierbar, also ausgeschlossen. Wenn nicht ausgeschlossen, wird es für jedes Zeichen getrennt.
Diese Funktion kann in allen Fällen verwendet werden.
print(list(flatten(l_2d)))
# [0, 1, 2, 3]
print(list(flatten(l_3d)))
# [0, 1, 2, 3, 4, 5, 6, 7]
print(list(flatten(l_mix)))
# [0, 1, 2, 3, 4]
Es spielt keine Rolle, ob verschiedene iterierbare Objekte wie Listen, Tupel und Bereich enthalten sind.
l_t_r_mix = [[0, 1], (2, 3), 4, range(5, 8)]
print(list(flatten(l_t_r_mix)))
# [0, 1, 2, 3, 4, 5, 6, 7]
Wenn Sie nur Listen verwalten möchten, müssen Sie keine Sammlungen importieren. Tupel und Bereich werden nicht abgeflacht, aber das reicht in den meisten Fällen aus.
def flatten_list(l):
for el in l:
if isinstance(el, list):
yield from flatten_list(el)
else:
yield el
print(list(flatten_list(l_2d)))
# [0, 1, 2, 3]
print(list(flatten_list(l_3d)))
# [0, 1, 2, 3, 4, 5, 6, 7]
print(list(flatten_list(l_mix)))
# [0, 1, 2, 3, 4]
print(list(flatten_list(l_t_r_mix)))
# [0, 1, (2, 3), 4, range(5, 8)]
Sie können mehrere Typen pro Tupel im zweiten Argument von isinstance() angeben.
def flatten_list_tuple_range(l):
for el in l:
if isinstance(el, (list, tuple, range)):
yield from flatten_list_tuple_range(el)
else:
yield el
print(list(flatten_list_tuple_range(l_t_r_mix)))
# [0, 1, 2, 3, 4, 5, 6, 7]