it-swarm.com.de

Wie erstelle ich eine flache Liste aus der Listenliste?

Ich frage mich, ob es eine Verknüpfung gibt, um eine einfache Liste aus der Liste der Listen in Python zu erstellen.

Ich kann das in einer for-Schleife machen, aber vielleicht gibt es ein paar coole "Einzeiler"? Ich habe es mit verkleinern versucht, aber ich bekomme 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'
2423
Emma

Gegeben eine Liste der Listen l,

flat_list = [item for sublist in l for item in sublist]

was bedeutet:

for sublist in l:
    for item in sublist:
        flat_list.append(item)

ist schneller als die bisher veröffentlichten Verknüpfungen. (l ist die Liste, die abgeflacht werden soll.)

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

Erläuterung: Die auf + basierenden Verknüpfungen (einschließlich der implizierten Verwendung in sum) sind notwendigerweise O(L**2), wenn L Unterlisten vorhanden sind. Da die Zwischenergebnisliste immer länger wird, wird bei jedem Schritt ein neues Zwischenergebnislistenobjekt zugewiesen Alle Elemente des vorherigen Zwischenergebnisses müssen kopiert werden (sowie einige neue am Ende hinzugefügt). Zur Vereinfachung und ohne tatsächlichen Verlust der Allgemeinheit sagen Sie, dass Sie L Unterlisten von jeweils I-Elementen haben: Die ersten I-Elemente werden L-1-mal hin- und hergeschickt, 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, d. h. I * (L**2)/2.

Das Listenverständnis generiert nur einmal eine Liste und kopiert jedes Element (vom ursprünglichen Wohnort bis zur Ergebnisliste) ebenfalls genau einmal.

3548
Alex Martelli

Sie können itertools.chain() verwenden:

>>> import itertools
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain(*list2d))

oder verwenden Sie bei Python> = 2.6 itertools.chain.from_iterable() , um die Liste nicht auszupacken

>>> import itertools
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain.from_iterable(list2d))

Dieser Ansatz ist wahrscheinlich lesbarer als [item for sublist in l for item in sublist] und scheint auch schneller zu sein:

[[email protected]]$ 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
[[email protected]]$ 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
[[email protected]]$ 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
[[email protected]]$ 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
[[email protected]]$ python --version
Python 2.7.3
1222
Shawn Chin

Anmerkung des Autors: Dies ist ineffizient. Aber Spaß, weil Monoids sind fantastisch. Es ist nicht für die Produktion von Python-Code geeignet.

>>> sum(l, [])
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Dies summiert nur die Elemente von iterable, die im ersten Argument übergeben wurden, und behandelt das zweite Argument als Anfangswert der Summe (wenn nicht angegeben, wird stattdessen 0 verwendet und dieser Fall gibt einen Fehler aus).

Da Sie verschachtelte Listen summieren, erhalten Sie [1,3]+[2,4] tatsächlich als Ergebnis von sum([[1,3],[2,4]],[]), was gleich [1,3,2,4] ist.

Beachten Sie, dass nur Listenlisten möglich sind. Für Listenlisten benötigen Sie eine andere Lösung.

709
Triptych

Ich habe die meisten Lösungsvorschläge mit perfplot getestet (ein Haustierprojekt von mir, im Wesentlichen ein Wrapper um timeit) und fand

functools.reduce(operator.iconcat, a, [])

die schnellste Lösung sein. (operator.iadd ist gleich schnell.)

 enter image description here


Code zum Reproduzieren des Diagramms:

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'
    )
227
Nico Schlömer
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 ändert x, anstatt einen nützlichen Wert zurückzugeben (den reduce() erwartet).

Eine schnellere Möglichkeit, die reduce-Version auszuführen, 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]
121
Greg Hewgill

Hier ein allgemeiner Ansatz, der für numbers, strings, nested - Listen und mixed -Container gilt.

Code

from collections import Iterable


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

Hinweis: In Python 3 kann yield from flatten(x)for sub_x in flatten(x): yield sub_x ersetzen.

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 wurde nach einem Rezept in Beazley, D. und B. Jones modifiziert. Rezept 4.14, Python Cookbook 3. Auflage, O'Reilly Media Inc. Sebastopol, CA: 2013.
  • Habe einen früheren SO post gefunden, möglicherweise die Originaldemonstration.
72
pylang

Ich nehme meine Aussage zurück. Summe ist nicht der Gewinner. Obwohl es schneller ist, wenn die Liste klein ist. Bei größeren Listen verschlechtert sich die Leistung jedoch erheblich.  

>>> 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 Summenversion läuft noch mehr als eine Minute und wurde noch nicht verarbeitet!

Für Medienlisten:

>>> 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

Verwenden von kleinen Listen und Zeit: Nummer = 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
34
Nadia Alramli

Wenn Sie eine Datenstruktur reduzieren möchten, bei der Sie nicht wissen, wie tief sie verschachtelt ist, können Sie iteration_utilities.deepflatten verwenden.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, also müssen Sie das Ergebnis in eine list umwandeln oder explizit darüber iterieren.


Um nur eine Ebene zu glätten, und wenn jedes Element selbst iterierbar ist, können Sie auch iteration_utilities.flatten verwenden, das selbst nur ein dünner Wrapper um itertools.chain.from_iterable ist:

>>> 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]

Um nur einige Timings hinzuzufügen (basierend auf der Antwort von Nico Schlömer, die die in dieser Antwort dargestellte Funktion nicht enthält):

 enter image description here

Es handelt sich um eine Protokollprotokolldarstellung, die für die große Bandbreite an Werten geeignet ist. Aus qualitativen Gründen: Weniger ist besser.

Die Ergebnisse zeigen, dass, wenn das iterable nur wenige innere iterables enthält, sum am schnellsten ist. Bei langen iterables haben jedoch nur itertools.chain.from_iterable, iteration_utilities.deepflatten oder das verschachtelte Verständnis eine angemessene Leistung, wobei itertools.chain.from_iterable die schnellste ist (wie bereits von Nico Schlömer bemerkt).

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 Haftungsausschluss: Ich bin der Autor dieser Bibliothek

31
MSeifert

Warum nutzt du das?

reduce(lambda x, y: x+y, l)

Das sollte gut funktionieren.

28
Andrea Ambu

Es scheint eine Verwechslung mit operator.add zu geben! Wenn Sie zwei Listen zusammen hinzufügen, lautet der korrekte Begriff concat und nicht add. operator.concat ist das, was Sie verwenden müssen.

Wenn Sie funktional denken, ist es so einfach:

>>> 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, dass der Sequenztyp reduziert wird. Wenn Sie einen Tuple angeben, erhalten Sie einen Tuple zurück. Versuchen wir es mit einer Liste:

>>> list2d = [[1, 2, 3],[4, 5, 6], [7], [8, 9]]
>>> reduce(operator.concat, list2d)
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Aha, du bekommst eine Liste zurück.

Wie wäre es mit der 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! Es ist jedoch 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
27
Meitham

Erwägen Sie die Installation des Pakets more_itertools .

> pip install more_itertools

Im Lieferumfang ist eine Implementierung für flatten ( source , aus den itertools-Rezepten ) enthalten:

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 können Sie mit more_itertools.collapse ( source , bereitgestellt von abarnet) kompliziertere, geschachtelte iterierbare Elemente abflachen.

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]
16
pylang

Der Grund, warum Ihre Funktion nicht funktioniert hat: Das extend erweitert das Array an Ort und Stelle und gibt es nicht zurück. Sie können immer noch x von Lambda zurückgeben, indem Sie einen Trick verwenden:

reduce(lambda x,y: x.extend(y) or x, l)

Hinweis: Erweitern ist effizienter als + in Listen.

16
Igor Krivokon

Erfinden Sie das Rad nicht neu, wenn Sie Django verwenden:

>>> 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))
12
Max Malysh
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]
11
Anil

Eine schlechte Funktion von Anils Funktion ist, dass der Benutzer das zweite Argument immer manuell als leere Liste [] angeben muss. Dies sollte stattdessen ein Standard sein. Aufgrund der Funktionsweise von Python-Objekten sollten diese in der Funktion und nicht in den Argumenten festgelegt werden.

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

Testen:

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]
10
Deleet

Folgendes scheint mir am einfachsten:

>>> 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]
9

matplotlib.cbook.flatten() funktioniert für verschachtelte Listen, auch wenn sie tiefer schachteln 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]

Dies ist 18x ​​schneller als der Unterstrich ._.

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
7
EL_DON

Die akzeptierte Antwort funktionierte für mich nicht, wenn es sich um textbasierte Listen variabler Längen handelte. Hier ist ein alternativer Ansatz, der für mich funktioniert hat.

l = ['aaa', 'bb', 'cccccc', ['xx', 'yyyyyyy']]

Akzeptierte Antwort, die nicht Arbeit erledigte:

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']

Neue vorgeschlagene Lösung, die hat für mich gearbeitet:

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']
7
user9074332

Man kann auch NumPy's flat verwenden:

import numpy as np
list(np.array(l).flat)

Bearbeiten 11/02/2016: Funktioniert nur, wenn Unterlisten identische Abmessungen haben.

7
mdh

Sie können numpy verwenden:
flat_list = list(np.concatenate(list_of_list))

6
A. Attia

Einfacher Code für underscore.py Paketlüfter

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 Abflachungsprobleme (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 underscore.py mit pip installieren

pip install underscore.py
4
Vu Anh
def flatten(alist):
    if alist == []:
        return []
    Elif type(alist) is not list:
        return [alist]
    else:
        return flatten(alist[0]) + flatten(alist[1:])
4
englealuze

Ein weiterer ungewöhnlicher Ansatz, der für hetero- und homogene Ganzzahlenlisten funktioniert:

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(',')]
4
tharndt

Schnellste Lösung, die ich gefunden habe (für große Liste trotzdem):

import numpy as np
#turn list into an array and flatten()
np.array(l).flatten()

Erledigt! Sie können es natürlich wieder in eine Liste umwandeln, indem Sie list (l) ausführen.

3
Canuck
flat_list = []
for i in list_of_list:
    flat_list+=i

Dieser Code funktioniert auch gut, da er nur die Liste vollständig erweitert. Es ist zwar sehr ähnlich, hat aber nur eine for-Schleife. Es ist also weniger komplex als das Hinzufügen von 2 für Schleifen.

3
Deepak Yadav

Wenn Sie bereit sind, ein wenig Geschwindigkeit für einen saubereren Look aufzugeben, können 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

Mehr erfahren Sie hier in den docs numpy.concatenate und numpy.ravel

3
mkultra

Eine einfache rekursive Methode, die reduce aus functools und den Operator add für Listen verwendet:

>>> 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 lst als Parameter an. Es durchläuft alle Elemente von lst, bis ganze Zahlen erreicht werden (kann auch int in float, str für andere Datentypen ändern), die zum Rückgabewert der äußersten Rekursion addiert werden.

Rekursion ist im Gegensatz zu Methoden wie for-Schleifen und Monaden eine allgemeine Lösung, die nicht durch die Listentiefe begrenzt ist. Eine Liste mit einer Tiefe von 5 kann beispielsweise wie l reduziert 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]
2
hash_purple

Ich bin vor kurzem auf eine Situation gestoßen, in der ich eine Mischung aus Strings und numerischen Daten in Unterlisten wie

test = ['591212948',
['special', 'assoc', 'of', 'Chicago', 'Jon', 'Doe'],
['Jon'],
['Doe'],
['fl'],
92001,
555555555,
'hello',
['hello2', 'a'],
'b',
['hello33', ['z', 'w'], 'b']]

wo Methoden wie flat_list = [item for sublist in test for item in sublist] nicht gearbeitet haben. Ich habe also die folgende Lösung für die Unterliste von 1+ Ebene gefunden

def concatList(data):
    results = []
    for rec in data:
        if type(rec) == list:
            results += rec
            results = concatList(results)
        else:
            results.append(rec)
    return results

Und das Ergebnis

In [38]: concatList(test)
Out[38]:
 Out[60]:
['591212948',
'special',
'assoc',
'of',
'Chicago',
'Jon',
'Doe',
'Jon',
'Doe',
'fl',
92001,
555555555,
'hello',
'hello2',
'a',
'b',
'hello33',
'z',
'w',
'b']
2
Jon

Dies ist vielleicht nicht der effizienteste Weg, aber ich dachte mir, ein Einliner (eigentlich ein Zweiliner) einzusetzen. Beide Versionen arbeiten mit verschachtelten Listen beliebiger Hierarchien und nutzen 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 zunächst in der Tiefe. Die Rekursion wird unterbrochen, bis ein Element gefunden wird, das kein Listenelement ist. Dann wird die lokale Variable flist erweitert und anschließend zum übergeordneten Element zurückgesetzt. Immer, wenn flist zurückgegeben wird, wird es im Listenverständnis um die flist des übergeordneten Objekts erweitert. Daher wird im Stammverzeichnis eine flache Liste zurückgegeben.

Die obige Liste erstellt mehrere lokale Listen und gibt diese zurück, um die Liste der übergeordneten Elemente zu erweitern. Ich denke, der Weg dahin könnte eine gloabl flist sein, wie unten beschrieben.

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 da

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

Obwohl ich zu diesem Zeitpunkt nicht sicher bin, was die Effizienz angeht.

2
phoxis

Note: Das Folgende gilt für Python 3.3+, da es yield_from verwendet. six ist auch ein Paket eines Drittanbieters, obwohl es stabil ist. Alternativ können Sie auch sys.version verwenden.


Im Fall von obj = [[1, 2,], [3, 4], [5, 6]] sind alle Lösungen hier gut, einschließlich Listenverständnis und itertools.chain.from_iterable.

Betrachten Sie jedoch diesen etwas komplexeren Fall:

>>> obj = [[1, 2, 3], [4, 5], 6, 'abc', [7], [8, [9, 10]]]

Hier gibt es mehrere Probleme:

  • Ein Element, 6, ist nur ein Skalar. Es ist nicht iterierbar, daher schlagen die obigen Routen hier fehl.
  • Ein Element, 'abc', ist ist technisch iterierbar (alle strs sind). Wenn Sie jedoch zwischen den Zeilen lesen, möchten Sie sie nicht als solche behandeln, sondern als ein einzelnes Element.
  • Das letzte Element, [8, [9, 10]], ist selbst eine verschachtelte Iteration. Grundlegendes Listenverständnis und chain.from_iterable extrahieren nur "1 Ebene nach unten".

Sie können dies wie folgt beheben:

>>> 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, ob das Unterelement (1) mit Iterable , einem ABC von itertools, iterierbar ist, möchten jedoch auch sicherstellen, dass (2) das Element nicht "string-like ist. "

2
Brad Solomon

Sie können rekursive Aufrufe des Stacks mit einer tatsächlichen Stack-Datenstruktur ganz einfach vermeiden.

alist = [1,[1,2],[1,2,[4,5,6],3, "33"]]
newlist = []

while len(alist) > 0 :
  templist = alist.pop()
  if type(templist) == type(list()) :
    while len(templist) > 0 :
      temp = templist.pop()
      if type(temp) == type(list()) :
        for x in temp :
          templist.append(x)
      else :
        newlist.append(temp)
  else :
    newlist.append(templist)
print(list(reversed(newlist)))
1
FredMan

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]
1
Saurabh Singh

Wirf meinen Hut in den Ring ...

B = [ [...], [...], ... ]
A = []
for i in B:
  A.extend(i)
1
donlan

Dies kann mit toolz.concat oder cytoolz.concat (cythonized Version, die in einigen Fällen schneller sein könnte) gemacht werden:

from cytoolz import concat
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(concat(l)) # or just `concat(l)` if one only wants to iterate over the items

Auf meinem Computer in Python 3.6 scheint dies fast so schnell wie [item for sublist in l for item in sublist] zu sein (die Importzeit wird dabei nicht berücksichtigt):

In [611]: %timeit L = [item for sublist in l for item in sublist]
695 ns ± 2.75 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [612]: %timeit L = [item for sublist in l for item in sublist]
701 ns ± 5.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [613]: %timeit L = list(concat(l))
719 ns ± 12 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [614]: %timeit L = list(concat(l))
719 ns ± 22.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

Die toolz-Version ist in der Tat langsamer:

In [618]: from toolz import concat

In [619]: %timeit L = list(concat(l))
845 ns ± 29 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [620]: %timeit L = list(concat(l))
833 ns ± 8.73 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
0
bli

Die Frage fragte nach einer coolen "Einzeiler" Antwort. Dann ist hier mein Beitrag in einfachem Python:

a = [[2,3,6],[False,'foo','bar','baz'],[3.1415],[],[0,0,'0']]
flat_a = [a[i][j] for i in range(len(a)) for j in range(len(a[i]))]
flat_a
[2, 3, 6, False, 'foo', 'bar', 'baz', 3.1415, 0, 0, '0']
0
Ramon

Meine Lösung (intuitiv und kurz):

def unnest(lists):
    unnested = []
    for l in lists:
        unnested = unnested + l
    return unnested
0
Manrique

Mit Dask können Sie eine Liste reduzieren/zusammenführen und dabei den zusätzlichen Vorteil der Speicherkonservierung erzielen. Dask verwendet einen verzögerten Speicher, der nur mit compute () aktiviert wird. Sie können also die Dask Bag-API in Ihrer Liste verwenden und sie am Ende berechnen (). Dokumentation: http://docs.dask.org/en/latest/bag-api.html

import dask.bag as db

my_list = [[1,2,3],[4,5,6],[7,8,9]]
my_list = db.from_sequence(my_list, npartitions = 1)
my_list = my_list.flatten().compute()

# [1,2,3,4,5,6,7,8,9]
0
N.Bell

Wenn Sie eine langsamere (Laufzeit-) Route einschlagen, sollten Sie weiter gehen, als mit der Zeichenfolge abzugleichen. Möglicherweise haben Sie eine verschachtelte Liste von Tupeln oder Tupel von Listen oder eine Sequenz eines benutzerdefinierten iterierbaren Typs.

Nimm einen Typ aus der Eingabesequenz und überprüfe diesen.

def iter_items(seq):
    """Yield items in a sequence."""
    input_type = type(seq)

    def items(subsequence):
        if type(subsequence) != input_type:
            yield subsequence
        else:
            for sub in subsequence:
                yield from items(sub)

    yield from items(seq)


>>> list(iter_items([(1, 2), [3, 4], "abc", [5, 6], [[[[[7]]]]]]))
[(1, 2), 3, 4, 'abc', 5, 6, 7]
0
Shay

@Deleet-Beispiel aufgeräumt

from collections import Iterable

def flatten(l, a=[]):
    for i in l:
        if isinstance(i, Iterable):
            flatten(i, a)
        else:
            a.append(i)
    return a

daList = [[1,4],[5,6],[23,22,234,2],[2], [ [[1,2],[1,2]],[[11,2],[11,22]] ] ]

print(flatten(daList))

Beispiel: https://repl.it/G8mb/0

0
Kevin Postal

sie können die Kettenklasse verwenden

chain.from_iterable(['ABC', 'DEF'])

ausgabe wäre: [A B C D E F]

Referenz: https://docs.python.org/2/library/itertools.html#itertools.chain

0
Balamurugan

Dies funktioniert mit beliebig verschachtelten Listen. Es kann leicht erweitert werden, um mit anderen Arten von Iterables zu arbeiten.

def flatten(seq):
    """list -> list                                                                                                                                                                           
    return a flattend list from an abitrarily nested list                                                                                                                                     
    """
    if not seq:
        return seq
    if not isinstance(seq[0], list):
        return [seq[0]] + flatten(seq[1:])
    return flatten(seq[0]) + flatten(seq[1:])

Probelauf

>>> flatten([1, [2, 3], [[[4, 5, 6], 7], [[8]]], 9])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
0
Xero Smith

Hier ist eine Funktion mit Rekursion, die auf jeder beliebigen verschachtelten Liste funktioniert.

def flatten(nested_lst):
    """ Return a list after transforming the inner lists
        so that it's a 1-D list.

    >>> flatten([[[],["a"],"a"],[["ab"],[],"abc"]])
    ['a', 'a', 'ab', 'abc']
    """
    if not isinstance(nested_lst, list):
        return(nested_lst)

    res = []
    for l in nested_lst:
        if not isinstance(l, list):
            res += [l]
        else:
            res += flatten(l)


    return(res)

>>> flatten([[[],["a"],"a"],[["ab"],[],"abc"]])
['a', 'a', 'ab', 'abc']
0
Abhishek Bhatia

ein weiterer lustiger Weg, dies zu tun:

from functools import reduce
from operator import add

li=[[1,2],[3,4]]
x= reduce(add, li)
0
sudeepgupta90

Wir können dasselbe tun, indem wir die grundlegenden Konzepte von Python verwenden 

nested_list=[10,20,[30,40,[50]],[80,[10,[20]],90],60]
flat_list=[]
def unpack(list1):
    for item in list1:
        try:
            len(item)
            unpack(item)
        except:
            flat_list.append(item)
unpack(nested_list)
print (flat_list)
0
abhi krishnan