So erstellen Sie eine flache Liste aus einer Liste von Listen
-
11-09-2019 - |
Frage
Ich frage mich, ob es in Python eine Verknüpfung gibt, um aus einer Liste von Listen eine einfache Liste zu erstellen.
Das kann ich in einem machen for
Schleife, aber vielleicht gibt es einen coolen „Einzeiler“?Ich habe es mit versucht reduzieren, aber ich erhalte eine Fehlermeldung.
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'
Lösung
eine Liste von Listen l
gegeben,
flat_list = [item for sublist in l for item in sublist]
Das bedeutet:
flat_list = []
for sublist in l:
for item in sublist:
flat_list.append(item)
ist schneller als die Verknüpfungen bisher geschrieben. (l
ist die Liste zu glätten.)
Hier ist die entsprechende Funktion:
flatten = lambda l: [item for sublist in l for item in sublist]
Als Beweis können Sie das timeit
Modul 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
Erläuterung: die Verknüpfungen basierend auf +
(einschließlich der impliziten Verwendung in sum
) sind, notwendigerweise O(L**2)
wenn L Sublisten gibt es - wie das Zwischenergebnis-Liste wird immer länger, sollte bei jedem ein neues Zwischenergebnis Listenobjekt wird (sowie ein paar neue am Ende hinzugefügt) zugeordnet, und alle Elemente in dem vorherigen müssen Zwischenergebnis kopiert werden. Also, für Einfachheit und ohne tatsächlichen Verlust der Allgemeinheit, sagen Sie L Sublisten I Einzelteile haben jeweils: die ersten ich Elemente kopiert hin und her L-1-mal, den zweiten I Artikel L-2-mal, und so weiter; Gesamtanzahl der Kopien ist I-mal die Summe von x für x von 1 bis L ausgeschlossen, d.h. I * (L**2)/2
.
Die Liste Verständnis erzeugt nur eine Liste, einmal und kopiert jedes Element über (von seinem ursprünglichen Wohnort in der Ergebnisliste) auch genau einmal.
Andere Tipps
Sie können mit itertools.chain()
:
>>> import itertools
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain(*list2d))
oder auf Python> = 2.6, verwenden Sie itertools.chain.from_iterable()
, die erfordert nicht die Liste Auspacken:
>>> import itertools
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain.from_iterable(list2d))
Dieser Ansatz ist wohl besser lesbar als [item for sublist in l for item in sublist]
und scheint schneller zu sein:
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99;import itertools' 'list(itertools.chain.from_iterable(l))'
10000 loops, best of 3: 24.2 usec per loop
[me@home]$ 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: 45.2 usec per loop
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 488 usec per loop
[me@home]$ 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: 522 usec per loop
[me@home]$ python --version
Python 2.7.3
Hinweis des Autors : Das ist ineffizient. Aber Spaß, weil Monoide sind genial. Es ist nicht geeignet für die Produktion Python-Code.
>>> sum(l, [])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Dieses fasst nur die Elemente der iterable im ersten Argument übergeben, zweite Argument als Anfangswert der Summe der Behandlung (wenn nicht angegeben, 0
wird verwendet, statt und dieser Fall wird Ihnen ein Fehler).
Weil Sie verschachtelte Listen summieren, die Sie tatsächlich [1,3]+[2,4]
als Folge des sum([[1,3],[2,4]],[])
erhalten, die [1,3,2,4]
gleich ist.
Beachten Sie, dass auf den Listen von Listen nur funktioniert. Für Listen von Listen von Listen, werden Sie eine andere Lösung benötigen.
Ich testete die meisten vorgeschlagenen Lösungen mit perfplot (ein Lieblingsprojekt von mir, im Wesentlichen ein Wrapper um timeit
) und fand
functools.reduce(operator.iconcat, a, [])
die schnellste Lösung. (operator.iadd
ist gleich schnell.)
Code, um das Grundstück zu reproduzieren:
import functools
import itertools
import numpy
import operator
import perfplot
def forfor(a):
return [item for sublist in a for item in sublist]
def sum_brackets(a):
return sum(a, [])
def functools_reduce(a):
return functools.reduce(operator.concat, a)
def functools_reduce_iconcat(a):
return functools.reduce(operator.iconcat, a, [])
def itertools_chain(a):
return list(itertools.chain.from_iterable(a))
def numpy_flat(a):
return list(numpy.array(a).flat)
def numpy_concatenate(a):
return list(numpy.concatenate(a))
perfplot.show(
setup=lambda n: [list(range(10))] * n,
kernels=[
forfor, sum_brackets, functools_reduce, functools_reduce_iconcat,
itertools_chain, numpy_flat, numpy_concatenate
],
n_range=[2**k for k in range(16)],
logx=True,
logy=True,
xlabel='num lists'
)
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 extend()
Methode in Ihrem Beispiel modifiziert x
stattdessen einen nützlichen Wert der Rücksendung (die reduce()
erwartet).
Ein schneller Weg, um die reduce
Version zu tun 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]
Hier ist ein allgemeiner Ansatz, der auf Zahlen gilt: , Strings , verschachtelt Listen und gemischt Container.
Code
#from typing import Iterable
from collections import Iterable # < py38
def flatten(items):
"""Yield items from any nested iterable; see Reference."""
for x in items:
if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
for sub_x in flatten(x):
yield sub_x
else:
yield x
Notizen :
- In Python 3
yield from flatten(x)
kannfor sub_x in flatten(x): yield sub_x
ersetzen - In Python 3.8, abstrakte Basisklassen bewegt von
collection.abc
zumtyping
Modul .
Demo
lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(flatten(lst)) # nested lists
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
mixed = [[1, [2]], (3, 4, {5, 6}, 7), 8, "9"] # numbers, strs, nested & mixed
list(flatten(mixed))
# [1, 2, 3, 4, 5, 6, 7, 8, '9']
Referenz
- Diese Lösung aus einem Rezept in Beazley, D. und B. Jones modifiziert. Rezept 4.14, Python-Kochbuch, 3. Auflage, O'Reilly Media Inc. Sebastopol, Kalifornien:.. 2013
- Gefunden eine frühere SO Post , möglicherweise die ursprüngliche Demonstration.
Wenn Sie eine Datenstruktur glätten wollen, wo Sie nicht wissen, wie tief sie verschachtelt ist man verwenden könnte? iteration_utilities.deepflatten
1
>>> from iteration_utilities import deepflatten
>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> list(deepflatten(l, depth=1))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> l = [[1, 2, 3], [4, [5, 6]], 7, [8, 9]]
>>> list(deepflatten(l))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Es ist ein Generator, so dass Sie das Ergebnis in einen list
werfen müssen oder explizit über sie iterieren.
Um nur eine Ebene abflachen und wenn jedes der Elemente selbst Iterable Sie können auch verwenden iteration_utilities.flatten
, die selbst nur eine dünne Hülle um itertools.chain.from_iterable
:
>>> from iteration_utilities import flatten
>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> list(flatten(l))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Nur einige Timings hinzufügen (basierend auf Nico Schlömer Antwort, die nicht die Funktion in dieser Antwort präsentiert haben ist):
Es ist ein log-log-Diagramm für den großen Bereich zur Aufnahme von Werten aufgespannt. Für die qualitative Argumentation: weniger ist besser
. Die Ergebnisse zeigen, dass, wenn die iterable nur wenige innere Iterables enthalten dann sum
schnellsten sein, aber für langen Iterables nur die itertools.chain.from_iterable
, iteration_utilities.deepflatten
oder das verschachtelte Verständnis hat angemessene Leistung mit itertools.chain.from_iterable
die schnellsten zu sein (wie schon bemerkt, von Nico Schlömer ).
from itertools import chain
from functools import reduce
from collections import Iterable # or from collections.abc import Iterable
import operator
from iteration_utilities import deepflatten
def nested_list_comprehension(lsts):
return [item for sublist in lsts for item in sublist]
def itertools_chain_from_iterable(lsts):
return list(chain.from_iterable(lsts))
def pythons_sum(lsts):
return sum(lsts, [])
def reduce_add(lsts):
return reduce(lambda x, y: x + y, lsts)
def pylangs_flatten(lsts):
return list(flatten(lsts))
def flatten(items):
"""Yield items from any nested iterable; see REF."""
for x in items:
if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
yield from flatten(x)
else:
yield x
def reduce_concat(lsts):
return reduce(operator.concat, lsts)
def iteration_utilities_deepflatten(lsts):
return list(deepflatten(lsts, depth=1))
from simple_benchmark import benchmark
b = benchmark(
[nested_list_comprehension, itertools_chain_from_iterable, pythons_sum, reduce_add,
pylangs_flatten, reduce_concat, iteration_utilities_deepflatten],
arguments={2**i: [[0]*5]*(2**i) for i in range(1, 13)},
argument_name='number of inner lists'
)
b.plot()
1 Disclaimer: Ich bin der Autor dieser Bibliothek
Ich nehme meine Aussage zurück. Summe ist nicht der Gewinner. Obwohl es schneller ist, wenn die Liste klein. Aber die Leistung verschlechtert sich deutlich bei größeren Listen.
>>> timeit.Timer(
'[item for sublist in l for item in sublist]',
'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10000'
).timeit(100)
2.0440959930419922
Die Summe Version noch für mehr als eine Minute läuft und es noch nicht getan hat, die Verarbeitung!
Für mittlere Listen:
>>> timeit.Timer(
'[item for sublist in l for item in sublist]',
'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
).timeit()
20.126545906066895
>>> timeit.Timer(
'reduce(lambda x,y: x+y,l)',
'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
).timeit()
22.242258071899414
>>> timeit.Timer(
'sum(l, [])',
'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
).timeit()
16.449732065200806
Mit kleinen Listen und timeit: Anzahl = 1000000
>>> timeit.Timer(
'[item for sublist in l for item in sublist]',
'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
).timeit()
2.4598159790039062
>>> timeit.Timer(
'reduce(lambda x,y: x+y,l)',
'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
).timeit()
1.5289170742034912
>>> timeit.Timer(
'sum(l, [])',
'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
).timeit()
1.0598428249359131
Es scheint eine Verwechslung mit operator.add
zu sein! Wenn Sie zwei Listen zusammen fügen, die korrekte Bezeichnung für das concat
ist, fügen Sie nicht. operator.concat
ist, was Sie verwenden müssen.
Wenn Sie funktional denken, es ist so einfach, wie dies ::
>>> from functools import reduce
>>> list2d = ((1, 2, 3), (4, 5, 6), (7,), (8, 9))
>>> reduce(operator.concat, list2d)
(1, 2, 3, 4, 5, 6, 7, 8, 9)
Sie sehen Hinsicht den Sequenztyp reduzieren, so dass, wenn Sie ein Tupel liefern, erhalten Sie ein Tupel zurück. Beginnen wir mit einer Liste versuchen ::
>>> list2d = [[1, 2, 3],[4, 5, 6], [7], [8, 9]]
>>> reduce(operator.concat, list2d)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Aha, erhalten Sie zurück eine Liste.
Wie wäre Leistung ::
>>> list2d = [[1, 2, 3],[4, 5, 6], [7], [8, 9]]
>>> %timeit list(itertools.chain.from_iterable(list2d))
1000000 loops, best of 3: 1.36 µs per loop
from_iterable
ist ziemlich schnell! Aber es ist kein Vergleich mit concat
zu reduzieren.
>>> list2d = ((1, 2, 3),(4, 5, 6), (7,), (8, 9))
>>> %timeit reduce(operator.concat, list2d)
1000000 loops, best of 3: 492 ns per loop
Warum verwenden Sie verlängern?
reduce(lambda x, y: x+y, l)
Das sollte funktionieren.
Installieren des more_itertools
Paket.
> pip install more_itertools
Es wird mit einer Implementierung für flatten
( Quelle , von der itertools Rezepte ):
import more_itertools
lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(more_itertools.flatten(lst))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
Ab Version 2.4, Sie glätten können komplizierter, verschachtelten Iterables mit Quelle , trugen durch abarnet).
lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(more_itertools.collapse(lst))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
lst = [[1, 2, 3], [[4, 5, 6]], [[[7]]], 8, 9] # complex nesting
list(more_itertools.collapse(lst))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
Der Grund Ihrer Funktion nicht funktioniert hat: die in-place erstreckt Array erweitern und es nicht zurück. Sie können immer noch x von Lambda zurückgeben, einigen Trick:
reduce(lambda x,y: x.extend(y) or x, l)
. Hinweis: erweitern ist effizienter als auf Listen +
Setzen Sie das Rad nicht neu erfinden, wenn Sie mit Django :
>>> from django.contrib.admin.utils import flatten
>>> l = [[1,2,3], [4,5], [6]]
>>> flatten(l)
>>> [1, 2, 3, 4, 5, 6]
... Pandas :
>>> from pandas.core.common import flatten
>>> list(flatten(l))
... itertools :
>>> import itertools
>>> flatten = itertools.chain.from_iterable
>>> list(flatten(l))
... Matplotlib
>>> from matplotlib.cbook import flatten
>>> list(flatten(l))
... Unipath :
>>> from unipath.path import flatten
>>> list(flatten(l))
... Setuptools :
>>> from setuptools.namespaces import flatten
>>> list(flatten(l))
def flatten(l, a):
for i in l:
if isinstance(i, list):
flatten(i, a)
else:
a.append(i)
return a
print(flatten([[[1, [1,1, [3, [4,5,]]]], 2, 3], [4, 5],6], []))
# [1, 1, 1, 3, 4, 5, 2, 3, 4, 5, 6]
Eine schlechte Eigenschaft von Anils Funktion oben ist, dass es den Benutzer erfordert immer manuell, um das zweite Argument angeben eine leere Liste []
zu sein. Dies sollte stattdessen eine Standard sein. Aufgrund der Art und Weise sollten diese Python-Objekten arbeiten, innerhalb der Funktion eingestellt werden, nicht in den Argumenten.
Hier ist eine Arbeitsfunktion:
def list_flatten(l, a=None):
#check a
if a is None:
#initialize with empty list
a = []
for i in l:
if isinstance(i, list):
list_flatten(i, a)
else:
a.append(i)
return a
Test:
In [2]: lst = [1, 2, [3], [[4]],[5,[6]]]
In [3]: lst
Out[3]: [1, 2, [3], [[4]], [5, [6]]]
In [11]: list_flatten(lst)
Out[11]: [1, 2, 3, 4, 5, 6]
matplotlib.cbook.flatten()
funktioniert für verschachtelte Listen, auch wenn diese tiefer verschachtelt sind als im Beispiel.
import matplotlib
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
print(list(matplotlib.cbook.flatten(l)))
l2 = [[1, 2, 3], [4, 5, 6], [7], [8, [9, 10, [11, 12, [13]]]]]
print list(matplotlib.cbook.flatten(l2))
Ergebnis:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
Das ist 18x schneller als underscore._.flatten:
Average time over 1000 trials of matplotlib.cbook.flatten: 2.55e-05 sec
Average time over 1000 trials of underscore._.flatten: 4.63e-04 sec
(time for underscore._)/(time for matplotlib.cbook) = 18.1233394636
Die akzeptierte Antwort nicht für mich arbeiten, wenn sie mit textbasierten Listen variabler Länge handelt. Hier ist ein alternativer Ansatz, die für mich arbeiten.
l = ['aaa', 'bb', 'cccccc', ['xx', 'yyyyyyy']]
akzeptierte Antwort, die hat nicht Arbeit:
flat_list = [item for sublist in l for item in sublist]
print(flat_list)
['a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'c', 'c', 'c', 'xx', 'yyyyyyy']
New vorgeschlagene Lösung, dass haben Arbeit für mich:
flat_list = []
_ = [flat_list.extend(item) if isinstance(item, list) else flat_list.append(item) for item in l if item]
print(flat_list)
['aaa', 'bb', 'cccccc', 'xx', 'yyyyyyy']
rekursive Version
x = [1,2,[3,4],[5,[6,[7]]],8,9,[10]]
def flatten_list(k):
result = list()
for i in k:
if isinstance(i,list):
#The isinstance() function checks if the object (first argument) is an
#instance or subclass of classinfo class (second argument)
result.extend(flatten_list(i)) #Recursive call
else:
result.append(i)
return result
flatten_list(x)
#result = [1,2,3,4,5,6,7,8,9,10]
scheint Nach einfachsten zu mir:
>>> import numpy as np
>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> print (np.concatenate(l))
[1 2 3 4 5 6 7 8 9]
Man kann auch verwenden NumPy Wohnung :
import numpy as np
list(np.array(l).flat)
Bearbeiten 2016.11.02: Dies funktioniert nur, wenn Sublisten identische Abmessungen
. Sie können mit numpy:
flat_list = list(np.concatenate(list_of_list))
Einfacher Code für underscore.py
Paket Fan
from underscore import _
_.flatten([[1, 2, 3], [4, 5, 6], [7], [8, 9]])
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
Es löst alle Probleme abflachen (kein Listenelement oder komplexe Verschachtelung)
from underscore import _
# 1 is none list item
# [2, [3]] is complex nesting
_.flatten([1, [2, [3]], [4, 5, 6], [7], [8, 9]])
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
Sie können installieren underscore.py
mit pip
pip install underscore.py
def flatten(alist):
if alist == []:
return []
elif type(alist) is not list:
return [alist]
else:
return flatten(alist[0]) + flatten(alist[1:])
flat_list = []
for i in list_of_list:
flat_list+=i
auch Dieser Code funktioniert gut, da es nur die Liste all Art und Weise erweitern. Obwohl es viel ähnlich ist, aber haben nur eine for-Schleife. So It weniger Komplexität hat als 2 Zugabe für Schleifen.
Wenn Sie bereit sind, eine winzige Menge an Geschwindigkeit für eine sauberere Aussehen zu geben, dann könnten Sie numpy.concatenate().tolist()
oder numpy.concatenate().ravel().tolist()
verwenden:
import numpy
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]] * 99
%timeit numpy.concatenate(l).ravel().tolist()
1000 loops, best of 3: 313 µs per loop
%timeit numpy.concatenate(l).tolist()
1000 loops, best of 3: 312 µs per loop
%timeit [item for sublist in l for item in sublist]
1000 loops, best of 3: 31.5 µs per loop
Sie können mehr hier in der Dokumentation erfahren Sie numpy.concatenate und numpy.ravel
Schnellste Lösung I (für große Liste sowieso) gefunden zu haben:
import numpy as np
#turn list into an array and flatten()
np.array(l).flatten()
Fertig! Sie können es natürlich umkehren in eine Liste von Liste Ausführen (l)
Dies ist möglicherweise nicht der effizienteste Weg sein, aber ich dachte, einen Einzeiler (eigentlich ein Zweizeiler) zu setzen. Beide Versionen werden auf beliebigen Hierarchie verschachtelt Listen arbeiten und nutzt Sprachfunktionen (Python3.5) und Rekursion.
def make_list_flat (l):
flist = []
flist.extend ([l]) if (type (l) is not list) else [flist.extend (make_list_flat (e)) for e in l]
return flist
a = [[1, 2], [[[[3, 4, 5], 6]]], 7, [8, [9, [10, 11], 12, [13, 14, [15, [[16, 17], 18]]]]]]
flist = make_list_flat(a)
print (flist)
Die Ausgabe ist
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
Dies funktioniert in einer Tiefen ersten Art und Weise. Die Rekursion geht nach unten, bis es eine nicht-Listenelement befindet, erstreckt sich dann die lokale Variable flist
und rollt dann zurück, um es an die Mutter. Jedes Mal, wenn flist
zurückgeführt wird, wird es an die Eltern flist
in der Liste Verständnis erweitert. Daher an der Wurzel, eine flache Liste zurückgegeben wird.
Das oben schafft man mehrere lokale Listen und gibt sie, die die Eltern Liste verwendet zu verlängern. Ich denke, der Weg, um dafür kann eine gloabl flist
, wie weiter unten erstellen.
a = [[1, 2], [[[[3, 4, 5], 6]]], 7, [8, [9, [10, 11], 12, [13, 14, [15, [[16, 17], 18]]]]]]
flist = []
def make_list_flat (l):
flist.extend ([l]) if (type (l) is not list) else [make_list_flat (e) for e in l]
make_list_flat(a)
print (flist)
Die Ausgabe ist wieder
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
Obwohl ich zu diesem Zeitpunkt über die Effizienz nicht sicher bin.
Hinweis : hier gilt für Python 3.3+, weil es verwendet yield_from
. six
ist auch ein Dritt Paket, obwohl es stabil ist. Alternativ können Sie sys.version
verwenden.
Im Fall von obj = [[1, 2,], [3, 4], [5, 6]]
, alle Lösungen hier sind gut, einschließlich Liste Verständnis und itertools.chain.from_iterable
.
Allerdings betrachtet diese etwas komplexen Fall:
>>> obj = [[1, 2, 3], [4, 5], 6, 'abc', [7], [8, [9, 10]]]
Es gibt mehrere Probleme hier:
- Ein Element,
6
, ist nur ein Skalar; es ist nicht durchsuchbar, so dass die oben genannten Strecken werden hier versagen. - Ein Element,
'abc'
, ist technisch iterable (allestr
s sind). Doch zwischen den Zeilen ein bisschen lesen, Sie nicht wollen, es als solches behandeln -. Sie es als ein einzelnes Element behandeln wollen - Das letzte Element,
[8, [9, 10]]
ist selbst eine verschachtelte iterable. Grundliste Verständnis undchain.from_iterable
nur extrahieren „1 Ebene nach unten.“
Sie können hier Abhilfe zu schaffen, wie folgt:
>>> from collections import Iterable
>>> from six import string_types
>>> def flatten(obj):
... for i in obj:
... if isinstance(i, Iterable) and not isinstance(i, string_types):
... yield from flatten(i)
... else:
... yield i
>>> list(flatten(obj))
[1, 2, 3, 4, 5, 6, 'abc', 7, 8, 9, 10]
Hier überprüfen Sie, dass das Unterelement (1) ist iterable mit Iterable
, ein ABC von itertools
, sondern will auch sicherstellen, dass (2) das Element nicht "String-like."
Ein weiterer ungewöhnlicher Ansatz, der für heterogene und homogene Listen von ganzen Zahlen arbeitet:
from typing import List
def flatten(l: list) -> List[int]:
"""Flatten an arbitrary deep nested list of lists of integers.
Examples:
>>> flatten([1, 2, [1, [10]]])
[1, 2, 1, 10]
Args:
l: Union[l, Union[int, List[int]]
Returns:
Flatted list of integer
"""
return [int(i.strip('[ ]')) for i in str(l).split(',')]
Eine einfache rekursive Methode reduce
von functools
und den add
Operator auf Listen:
>>> from functools import reduce
>>> from operator import add
>>> flatten = lambda lst: [lst] if type(lst) is int else reduce(add, [flatten(ele) for ele in lst])
>>> flatten(l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Die Funktion flatten
nimmt in lst
als Parameter. Es Schleifen alle Elemente lst
bis ganzen Zahlen erreicht (auch int
ändern float
, str
usw. für andere Datentypen), die auf den Rückgabewert der äußersten Rekursion hinzugefügt werden.
Rekursion, im Gegensatz zu Methoden wie for
Schleifen und Monaden, ist, dass es ist eine allgemeine Lösung nicht von der Liste Tiefe begrenzt . Zum Beispiel kann eine Liste mit einer Tiefe von 5 auf die gleiche Weise wie l
abgeflacht werden:
>>> l2 = [[3, [1, 2], [[[6], 5], 4, 0], 7, [[8]], [9, 10]]]
>>> flatten(l2)
[3, 1, 2, 6, 5, 4, 0, 7, 8, 9, 10]