Reduzieren Sie eine unregelmäßige Liste von Listen

440

Ja, ich weiß, dass dieses Thema bereits behandelt wurde ( hier , hier , hier , hier ), aber soweit ich weiß, schlagen alle Lösungen außer einer auf einer Liste wie dieser fehl:

L = [[[1, 2, 3], [4, 5]], 6]

Wo die gewünschte Ausgabe ist

[1, 2, 3, 4, 5, 6]

Oder vielleicht sogar noch besser, ein Iterator. Die einzige Lösung, die ich für eine beliebige Verschachtelung gesehen habe, ist diese Frage :

def flatten(x):
    result = []
    for el in x:
        if hasattr(el, "__iter__") and not isinstance(el, basestring):
            result.extend(flatten(el))
        else:
            result.append(el)
    return result

flatten(L)

Ist das das beste Modell? Habe ich etwas übersehen? Irgendwelche Probleme?

telliott99
quelle
16
Die Tatsache, dass es so viele Antworten und so viele Maßnahmen zu dieser Frage gibt, legt wirklich nahe, dass dies irgendwo eine eingebaute Funktion sein sollte, oder? Es ist besonders schade, dass compiler.ast aus Python 3.0 entfernt wurde
Mittenchops
3
Ich würde sagen, dass Python wirklich eine ungebrochene Rekursion braucht und keine andere eingebaute.
Ton
2
@Mittenchops: stimme überhaupt nicht zu, dass Leute mit offensichtlich schlechten APIs / übermäßig komplizierten Datenstrukturen arbeiten (nur ein Hinweis: list s sollen homogen sein), nicht bedeuten, dass es ein Python-Fehler ist und wir für diese Aufgabe eine integrierte Funktion benötigen
Azat Ibrakov
1
Wenn Sie es sich leisten können, Ihrem Projekt ein Paket hinzuzufügen, ist die Lösung more_itertools.collapse wahrscheinlich die beste Lösung. Aus dieser Antwort: stackoverflow.com/a/40938883/3844376
viddik13

Antworten:

382

Die Verwendung von Generatorfunktionen kann das Lesen Ihres Beispiels erleichtern und wahrscheinlich die Leistung steigern.

Python 2

def flatten(l):
    for el in l:
        if isinstance(el, collections.Iterable) and not isinstance(el, basestring):
            for sub in flatten(el):
                yield sub
        else:
            yield el

Ich habe das in 2.6 hinzugefügte Iterable ABC verwendet .

Python 3

In Python 3 ist das basestringnicht mehr, aber Sie können ein Tupel von strund verwenden bytes, um dort den gleichen Effekt zu erzielen.

Der yield fromBediener gibt einen Artikel einzeln von einem Generator zurück. Diese Syntax zum Delegieren an einen Subgenerator wurde in 3.3 hinzugefügt

def flatten(l):
    for el in l:
        if isinstance(el, collections.Iterable) and not isinstance(el, (str, bytes)):
            yield from flatten(el)
        else:
            yield el
Cristian
quelle
6
Von allen Vorschlägen auf dieser Seite ist dies der einzige, der diese Liste l = ([[chr(i),chr(i-32)] for i in xrange(ord('a'), ord('z')+1)] + range(0,9))im Handumdrehen abgeflacht hat, als ich dies tat list(flatten(l)). Alle anderen würden anfangen zu arbeiten und ewig dauern!
Nemesisfixx
7
Dies glättet auch Wörterbücher. Vielleicht möchten Sie collections.Sequencestatt verwenden collections.Iteratable?
Josch
1
Dies funktioniert nicht mit Dingen, die anfangs keine Listen sind, z for i in flatten(42): print (i). Dies könnte behoben werden, indem der isinstance-test und die else-Klausel außerhalb der for el-loop verschoben werden. (Dann könnten Sie alles darauf werfen, und es würde eine abgeflachte Liste daraus machen)
RolKau
6
Für Python 3.7 ist die Verwendung von collections.Iterableveraltet. Verwenden Sie collections.abc.Iterablestattdessen.
Morgengrauen
5
In der Tat ist eine Rekursion niemals erforderlich. In diesem speziellen Fall ist die Verwendung von Rekursion nicht die beste Lösung, da sie auf tief verschachtelten Listen (Tiefe> 1000) abstürzt. Aber wenn Sie nicht auf etwas Sicheres abzielen, ist die rekursive Funktion besser, da sie viel einfacher zu lesen / schreiben ist.
Cglacet
50

Meine Lösung:

import collections


def flatten(x):
    if isinstance(x, collections.Iterable):
        return [a for i in x for a in flatten(i)]
    else:
        return [x]

Ein bisschen prägnanter, aber ziemlich gleich.

Josh Lee
quelle
5
Sie können dies tun, ohne etwas zu importieren, wenn Sie nur try: iter(x)testen möchten, ob es iterierbar ist. Aber ich denke nicht, dass es ein Nachteil ist, ein stdlib-Modul importieren zu müssen.
Abarnert
8
Wert zu beachten , dass diese Lösung nur , wenn alle Einzelteile sind vom Typ arbeitetint
alfasin
1
Könnte es prägnanter machen, def flatten(x): return [a for i in x for a in flatten(i)] if isinstance(x, collections.Iterable) else [x]aber die Lesbarkeit könnte hier subjektiv sein.
Null
4
Dies funktioniert bei Zeichenfolgen nicht, da Zeichenfolgen auch iterierbar sind. Ersetzen Sie die Bedingung durchif isinstance(x, collections.Iterable) and not isinstance(x, basestring)
aandis
36

Generator mit Rekursion und Ententypisierung (aktualisiert für Python 3):

def flatten(L):
    for item in L:
        try:
            yield from flatten(item)
        except TypeError:
            yield item

list(flatten([[[1, 2, 3], [4, 5]], 6]))
>>>[1, 2, 3, 4, 5, 6]
Dansalmo
quelle
1
Danke, das funktioniert gut für Python 3. Für 2.x wird das vorherige benötigt: for i in flatten(item): yield i
Dansalmo
Liste (Abflachen ([['X'], 'Y'])) schlägt bei 2.X-Variante fehl
sten
@ user1019129 siehe meinen Kommentar über
Ihrem
Ja, es schlägt mit dem Zyklus fehl. Ich denke, weil ein String auch ein "Array" von Zeichen ist
Sten
35

Generatorversion der nicht rekursiven Lösung von @ unutbu, wie von @Andrew in einem Kommentar angefordert:

def genflat(l, ltypes=collections.Sequence):
    l = list(l)
    i = 0
    while i < len(l):
        while isinstance(l[i], ltypes):
            if not l[i]:
                l.pop(i)
                i -= 1
                break
            else:
                l[i:i + 1] = l[i]
        yield l[i]
        i += 1

Leicht vereinfachte Version dieses Generators:

def genflat(l, ltypes=collections.Sequence):
    l = list(l)
    while l:
        while l and isinstance(l[0], ltypes):
            l[0:1] = l[0]
        if l: yield l.pop(0)
Alex Martelli
quelle
Es handelt sich um eine Vorbestellung des Baums, der aus den verschachtelten Listen besteht. Nur die Blätter werden zurückgegeben. Beachten Sie, dass diese Implementierung die ursprüngliche Datenstruktur zum Guten oder Schlechten verwendet. Es könnte Spaß machen, einen zu schreiben, der den ursprünglichen Baum beibehält, aber auch die Listeneinträge nicht kopieren muss.
Andrew Wagner
6
Ich denke, Sie müssen auf Zeichenfolgen testen - z. B. "und nicht isinstance (l [0], basestring)" wie in Cristians Lösung hinzufügen. Andernfalls erhalten Sie eine Endlosschleife um l [0: 1] = l [0]
c-urchin
Dies ist ein gutes Beispiel für die Erstellung eines Generators, aber wie c-urchin erwähnt, schlägt der Algorithmus selbst fehl, wenn die Sequenz Zeichenfolgen enthält.
Daniel 'Dang' Griffith
28

Hier ist meine funktionale Version von rekursivem Abflachen, die sowohl Tupel als auch Listen verarbeitet und es Ihnen ermöglicht, eine beliebige Mischung von Positionsargumenten einzugeben. Gibt einen Generator zurück, der die gesamte Sequenz in der Reihenfolge arg by arg erzeugt:

flatten = lambda *n: (e for a in n
    for e in (flatten(*a) if isinstance(a, (tuple, list)) else (a,)))

Verwendungszweck:

l1 = ['a', ['b', ('c', 'd')]]
l2 = [0, 1, (2, 3), [[4, 5, (6, 7, (8,), [9]), 10]], (11,)]
print list(flatten(l1, -2, -1, l2))
['a', 'b', 'c', 'd', -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
samplebias
quelle
1
große Lösung, aber wäre viel hilfreich , wenn Sie etwas Kommentar zu beschreiben , was hinzugefügt e, a, nbeziehen sich auf
Kristof Pal
2
@WolfgangKuehne: Versuchen argsfür n, intermediate(oder die kürzere midoder Sie es vorziehen könnten element) für aund resultfür e, so:flatten = lambda *args: (result for mid in args for result in (flatten(*mid) if isinstance(mid, (tuple, list)) else (mid,)))
Pausiert bis auf weiteres.
Dies ist deutlich schneller als compiler.ast.flatten. Großartiger, kompakter Code, funktioniert für jeden (glaube ich) Objekttyp.
bcdan
Wow, das sollte die am besten gewählte und akzeptierte Antwort sein ... funktioniert wie ein Zauber!
U10-Forward
27

Diese Version von flattenvermeidet das Rekursionslimit von Python (und arbeitet daher mit beliebig tiefen, verschachtelten Iterablen). Es ist ein Generator, der Strings und beliebige iterable (auch unendliche) verarbeiten kann.

import itertools as IT
import collections

def flatten(iterable, ltypes=collections.Iterable):
    remainder = iter(iterable)
    while True:
        first = next(remainder)
        if isinstance(first, ltypes) and not isinstance(first, (str, bytes)):
            remainder = IT.chain(first, remainder)
        else:
            yield first

Hier sind einige Beispiele, die seine Verwendung demonstrieren:

print(list(IT.islice(flatten(IT.repeat(1)),10)))
# [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

print(list(IT.islice(flatten(IT.chain(IT.repeat(2,3),
                                       {10,20,30},
                                       'foo bar'.split(),
                                       IT.repeat(1),)),10)))
# [2, 2, 2, 10, 20, 30, 'foo', 'bar', 1, 1]

print(list(flatten([[1,2,[3,4]]])))
# [1, 2, 3, 4]

seq = ([[chr(i),chr(i-32)] for i in range(ord('a'), ord('z')+1)] + list(range(0,9)))
print(list(flatten(seq)))
# ['a', 'A', 'b', 'B', 'c', 'C', 'd', 'D', 'e', 'E', 'f', 'F', 'g', 'G', 'h', 'H',
# 'i', 'I', 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N', 'o', 'O', 'p', 'P',
# 'q', 'Q', 'r', 'R', 's', 'S', 't', 'T', 'u', 'U', 'v', 'V', 'w', 'W', 'x', 'X',
# 'y', 'Y', 'z', 'Z', 0, 1, 2, 3, 4, 5, 6, 7, 8]

Obwohl flattenes mit unendlichen Generatoren umgehen kann, kann es nicht mit unendlichen Verschachtelungen umgehen:

def infinitely_nested():
    while True:
        yield IT.chain(infinitely_nested(), IT.repeat(1))

print(list(IT.islice(flatten(infinitely_nested()), 10)))
# hangs
unutbu
quelle
1
Gibt es einen Konsens darüber, ob ABC Iterable oder ABC Sequence verwendet werden soll?
wim
sets, dicts, deques, listiterators, generators, Dateihandies und benutzerdefinierte Klassen mit __iter__definierten sind alle Instanzen collections.Iterable, aber nicht collections.Sequence. Das Ergebnis der Abflachung von a dictist etwas zweifelhaft, aber ansonsten denke ich, collections.Iterableist eine bessere Standardeinstellung als collections.Sequence. Es ist definitiv liberaler.
Unutbu
@wim: Ein Problem bei der Verwendung collections.Iterableist, dass dies unendliche Generatoren umfasst. Ich habe meine Antwort in diesem Fall geändert.
Unutbu
1
Dies scheint für das 3. und 4. Beispiel nicht zu funktionieren. Es wirft StopIteration. Auch sieht aus wie while True: first = next(remainder) könnte durch ersetzt werden for first in remainder:.
Georgy
@Georgy Dies könnte durch Einkapseln des Abflachungskörpers in a behoben werden try-except StopIteration block.
Baduker
12

Hier ist eine weitere Antwort, die noch interessanter ist ...

import re

def Flatten(TheList):
    a = str(TheList)
    b,crap = re.subn(r'[\[,\]]', ' ', a)
    c = b.split()
    d = [int(x) for x in c]

    return(d)

Grundsätzlich konvertiert es die verschachtelte Liste in eine Zeichenfolge, entfernt die verschachtelte Syntax mithilfe eines regulären Ausdrucks und konvertiert das Ergebnis dann zurück in eine (abgeflachte) Liste.

Lehm
quelle
Wenn Sie versuchen , das andere als int - Werte etwas zu verallgemeinern, wird es Spaß machen , mit zB [['C=64', 'APPLE ]['], ['Amiga', 'Mac', 'ST']]:) Auf der anderen Seite wird eine Liste gegeben , die sich enthält, wird es ein wenig besser als die anderen Antworten, die Erhöhung ein Ausnahme anstatt nur zu schleifen, bis Ihnen der Speicher ausgeht / rekursiv, bis Sie den Stapel erschöpft haben ...
Abarnert
Bei der ursprünglichen Eingabeaufforderung ging es darum, eine Liste von Ganzzahlen zu reduzieren. Wenn Sie nur das Listenverständnis in d = [x für x in c] ändern, sollte es für Ihre Stichprobe gut funktionieren.
Ton
Erstens [x for x in c]ist es nur eine langsame und ausführliche Möglichkeit, eine Kopie davon zu cerstellen. Warum sollten Sie das tun? Zweitens wird der Code eindeutig konvertieren gehen 'APPLE ]['in 'APPLE ', weil es nicht zu zitieren umgehen kann , nimmt sie nur alle Klammern Liste Klammern sind.
Abarnert
Ha! So wie Ihr Kommentar auf meinem Computer formatiert wurde, wusste ich nicht einmal, dass es sich um Apple II handeln sollte, wie es auf den alten Computern angezeigt wurde. Auf jeden Fall ist meine Antwort auf Ihre beiden Fragen, dass diese Übung - für mich - lediglich ein Experiment ist, um eine kreative Lösung zum Reduzieren einer Liste zu finden. Ich bin mir nicht sicher, ob ich es verallgemeinern würde, um jede Liste da draußen zu reduzieren.
Ton
Sie müssen nur arr_str = str(arr)und dann [int(s) for s in re.findall(r'\d+', arr_str)]wirklich. Siehe github.com/jorgeorpinel/flatten_nested_lists/blob/master/…
Jorge Orpinel
10
def flatten(xs):
    res = []
    def loop(ys):
        for i in ys:
            if isinstance(i, list):
                loop(i)
            else:
                res.append(i)
    loop(xs)
    return res
kev
quelle
8

Sie können deepflattenaus dem Drittanbieter-Paket verwenden iteration_utilities:

>>> from iteration_utilities import deepflatten
>>> L = [[[1, 2, 3], [4, 5]], 6]
>>> list(deepflatten(L))
[1, 2, 3, 4, 5, 6]

>>> list(deepflatten(L, types=list))  # only flatten "inner" lists
[1, 2, 3, 4, 5, 6]

Da es sich um einen Iterator handelt, müssen Sie ihn iterieren (z. B. indem Sie ihn mit listeiner Schleife umschließen oder in einer Schleife verwenden). Intern wird ein iterativer Ansatz anstelle eines rekursiven Ansatzes verwendet und als C-Erweiterung geschrieben, sodass er schneller sein kann als reine Python-Ansätze:

>>> %timeit list(deepflatten(L))
12.6 µs ± 298 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
>>> %timeit list(deepflatten(L, types=list))
8.7 µs ± 139 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

>>> %timeit list(flatten(L))   # Cristian - Python 3.x approach from https://stackoverflow.com/a/2158532/5393381
86.4 µs ± 4.42 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

>>> %timeit list(flatten(L))   # Josh Lee - https://stackoverflow.com/a/2158522/5393381
107 µs ± 2.99 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

>>> %timeit list(genflat(L, list))  # Alex Martelli - https://stackoverflow.com/a/2159079/5393381
23.1 µs ± 710 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Ich bin der Autor der iteration_utilitiesBibliothek.

MSeifert
quelle
7

Es hat Spaß gemacht, eine Funktion zu erstellen, die unregelmäßige Listen in Python reduzieren kann, aber dafür ist Python natürlich gedacht (damit das Programmieren Spaß macht). Der folgende Generator funktioniert mit einigen Einschränkungen ziemlich gut:

def flatten(iterable):
    try:
        for item in iterable:
            yield from flatten(item)
    except TypeError:
        yield iterable

Es wird Datentypen flach , dass Sie allein gelassen möchten (wie bytearray, bytesund strObjekte). Der Code beruht auch auf der Tatsache, dass das Anfordern eines Iterators von einem nicht iterierbaren Code a auslöst TypeError.

>>> L = [[[1, 2, 3], [4, 5]], 6]
>>> def flatten(iterable):
    try:
        for item in iterable:
            yield from flatten(item)
    except TypeError:
        yield iterable


>>> list(flatten(L))
[1, 2, 3, 4, 5, 6]
>>>

Bearbeiten:

Ich bin mit der vorherigen Implementierung nicht einverstanden. Das Problem ist, dass Sie nicht in der Lage sein sollten, etwas zu reduzieren, das nicht iterierbar ist. Es ist verwirrend und vermittelt den falschen Eindruck des Arguments.

>>> list(flatten(123))
[123]
>>>

Der folgende Generator ist fast der gleiche wie der erste, hat jedoch nicht das Problem, ein nicht iterierbares Objekt zu reduzieren. Es schlägt fehl, wie man es erwarten würde, wenn ein unangemessenes Argument dafür gegeben wird.

def flatten(iterable):
    for item in iterable:
        try:
            yield from flatten(item)
        except TypeError:
            yield item

Das Testen des Generators funktioniert einwandfrei mit der bereitgestellten Liste. Der neue Code löst jedoch ein aus, TypeErrorwenn ihm ein nicht iterierbares Objekt zugewiesen wird. Im Folgenden werden Beispiele für das neue Verhalten gezeigt.

>>> L = [[[1, 2, 3], [4, 5]], 6]
>>> list(flatten(L))
[1, 2, 3, 4, 5, 6]
>>> list(flatten(123))
Traceback (most recent call last):
  File "<pyshell#32>", line 1, in <module>
    list(flatten(123))
  File "<pyshell#27>", line 2, in flatten
    for item in iterable:
TypeError: 'int' object is not iterable
>>>
Noctis Skytower
quelle
5

Obwohl eine elegante und sehr pythonische Antwort ausgewählt wurde, würde ich meine Lösung nur zur Überprüfung vorstellen:

def flat(l):
    ret = []
    for i in l:
        if isinstance(i, list) or isinstance(i, tuple):
            ret.extend(flat(i))
        else:
            ret.append(i)
    return ret

Bitte sagen Sie, wie gut oder schlecht dieser Code ist.

Xolve
quelle
1
Verwenden Sie isinstance(i, (tuple, list)). Das Initialisieren leerer Variablen ist für mich ein Flag, um nach alternativen
Codestrukturen
3
return type(l)(ret)Sie erhalten auch den gleichen Containertyp zurück, der übergeben wurde. :)
Dash-Tom-Bang
@ dash-tom-bang Kannst du bitte etwas näher erläutern, was es bedeutet?
Xolve
1
Wenn Sie eine Liste übergeben, möchten Sie wahrscheinlich eine Liste zurück. Wenn Sie ein Tupel übergeben, möchten Sie wahrscheinlich ein Tupel zurück. Wenn Sie in einem Mischmasch der beiden vorbeikommen, erhalten Sie alles, was die äußere Umschließung war.
Dash-Tom-Bang
4

Ich bevorzuge einfache Antworten. Keine Generatoren. Keine Rekursion oder Rekursionsgrenzen. Nur Iteration:

def flatten(TheList):
    listIsNested = True

    while listIsNested:                 #outer loop
        keepChecking = False
        Temp = []

        for element in TheList:         #inner loop
            if isinstance(element,list):
                Temp.extend(element)
                keepChecking = True
            else:
                Temp.append(element)

        listIsNested = keepChecking     #determine if outer loop exits
        TheList = Temp[:]

    return TheList

Dies funktioniert mit zwei Listen: einer inneren for-Schleife und einer äußeren while-Schleife.

Die innere for-Schleife durchläuft die Liste. Wenn ein Listenelement gefunden wird, verwendet es (1) list.extend (), um diesen Teil einer Verschachtelungsebene zu reduzieren, und (2) schaltet keepChecking auf True. Keepchecking wird verwendet, um die äußere while-Schleife zu steuern. Wenn die äußere Schleife auf true gesetzt wird, wird die innere Schleife für einen weiteren Durchgang ausgelöst.

Diese Durchläufe werden so lange ausgeführt, bis keine verschachtelten Listen mehr gefunden werden. Wenn schließlich ein Pass auftritt, bei dem keiner gefunden wird, wird keepChecking nie auf true ausgelöst, was bedeutet, dass listIsNested false bleibt und die äußere while-Schleife beendet wird.

Die abgeflachte Liste wird dann zurückgegeben.

Testlauf

flatten([1,2,3,4,[100,200,300,[1000,2000,3000]]])

[1, 2, 3, 4, 100, 200, 300, 1000, 2000, 3000]

Lehm
quelle
Ich mag auch einfach. In diesem Fall durchlaufen Sie die Liste jedoch so oft, wie es Verschachtelungen oder Ebenen gibt. Könnte teuer werden.
Telliott99
@ telliott99: Sie haben Recht, wenn Ihre Listen wirklich groß und / oder in großen Tiefen verschachtelt sind. Wenn dies jedoch nicht der Fall ist, funktioniert die einfachere Lösung genauso gut und ohne die tiefe Magie einiger anderer Antworten. Es gibt einen Platz für mehrstufige rekursive Generatorverständnisse, aber ich bin nicht davon überzeugt, dass Sie dort zuerst suchen sollten. (Ich denke, Sie wissen, wo ich in der Debatte "Schlimmer ist besser" falle.)
Lehm
@ telliott99: Oder anders ausgedrückt, Sie müssen nicht versuchen, meine Lösung zu "groken". Wenn Leistung kein Engpass ist, was ist für Sie als Programmierer am wichtigsten?
Ton
Einfachere Lösungen haben weniger Logik. Rekursion ist ein ziemlich grundlegendes Programmierkonstrukt, mit dem sich jeder, der sich als Programmierer betrachtet, völlig wohl fühlen sollte. Generatoren sind in hohem Maße der Python-Weg und (zusammen mit dem Verständnis) etwas, das jeder professionelle Python-Programmierer sofort verstehen sollte.
Dash-Tom-Bang
1
Ich stimme der Rekursion zu. Als ich meine Antwort schrieb, brach Python bei 1000 Zyklen immer noch die Rekursion. Haben sie das geändert? Als professioneller Python-Programmierer bin ich das nicht. Außerdem stelle ich mir vor, dass viele Leute, die in Python programmieren, dies nicht in Vollzeit tun.
Ton
4

Hier ist eine einfache Funktion, die Listen beliebiger Tiefe abflacht. Keine Rekursion, um einen Stapelüberlauf zu vermeiden.

from copy import deepcopy

def flatten_list(nested_list):
    """Flatten an arbitrarily nested list, without recursion (to avoid
    stack overflows). Returns a new list, the original list is unchanged.

    >> list(flatten_list([1, 2, 3, [4], [], [[[[[[[[[5]]]]]]]]]]))
    [1, 2, 3, 4, 5]
    >> list(flatten_list([[1, 2], 3]))
    [1, 2, 3]

    """
    nested_list = deepcopy(nested_list)

    while nested_list:
        sublist = nested_list.pop(0)

        if isinstance(sublist, list):
            nested_list = sublist + nested_list
        else:
            yield sublist
Wilfred Hughes
quelle
Ja! Sehr ähnlich zu meinem Code bei github.com/jorgeorpinel/flatten_nested_lists/blob/master/…
Jorge Orpinel
3

Ich bin überrascht, dass niemand daran gedacht hat. Verdammte Rekursion Ich bekomme nicht die rekursiven Antworten, die die fortgeschrittenen Leute hier gemacht haben. Jedenfalls ist hier mein Versuch dazu. Einschränkung ist, dass es sehr spezifisch für den Anwendungsfall des OP ist

import re

L = [[[1, 2, 3], [4, 5]], 6]
flattened_list = re.sub("[\[\]]", "", str(L)).replace(" ", "").split(",")
new_list = list(map(int, flattened_list))
print(new_list)

Ausgabe:

[1, 2, 3, 4, 5, 6]
Zion
quelle
3

Ich habe hier nicht alle bereits verfügbaren Antworten durchgesehen, aber hier ist ein Einzeiler, den ich mir ausgedacht habe und der von Lisps Art der Erst- und Restlistenverarbeitung übernommen wurde

def flatten(l): return flatten(l[0]) + (flatten(l[1:]) if len(l) > 1 else []) if type(l) is list else [l]

Hier ist ein einfacher und ein nicht so einfacher Fall -

>>> flatten([1,[2,3],4])
[1, 2, 3, 4]

>>> flatten([1, [2, 3], 4, [5, [6, {'name': 'some_name', 'age':30}, 7]], [8, 9, [10, [11, [12, [13, {'some', 'set'}, 14, [15, 'some_string'], 16], 17, 18], 19], 20], 21, 22, [23, 24], 25], 26, 27, 28, 29, 30])
[1, 2, 3, 4, 5, 6, {'age': 30, 'name': 'some_name'}, 7, 8, 9, 10, 11, 12, 13, set(['set', 'some']), 14, 15, 'some_string', 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
>>> 
Shreyas
quelle
Es ist kein Einzeiler. Egal wie viel Sie versuchen, es in eine zu passen, das def foo():ist eine separate Zeile. Auch das ist sehr unlesbar.
CS95
Ich habe den Code einzeilig gemacht und weitere Umgestaltungen vorgenommen. (Die Bearbeitung steht noch aus, während ich dies schreibe.) Diese spezielle Methode schien mir sehr lesbar zu sein, obwohl der ursprüngliche Code einige Umgestaltungen benötigte.
Emilio M Bumachar
3

Wenn Sie versuchen, eine solche Frage zu beantworten, müssen Sie wirklich die Einschränkungen des Codes angeben, den Sie als Lösung vorschlagen. Wenn es nur um Leistungen ginge, würde es mir nichts ausmachen, aber die meisten als Lösung vorgeschlagenen Codes (einschließlich der akzeptierten Antwort) können keine Liste mit einer Tiefe von mehr als 1000 abflachen.

Wenn ich die meisten Codes sage sage, meine ich alle Codes, die irgendeine Form der Rekursion verwenden (oder eine rekursive Standardbibliotheksfunktion aufrufen). Alle diese Codes schlagen fehl, da der (Aufruf-) Stapel für jeden rekursiven Aufruf um eine Einheit wächst und der (Standard-) Python-Aufrufstapel eine Größe von 1000 hat.

Wenn Sie mit dem Aufrufstapel nicht allzu vertraut sind, hilft möglicherweise Folgendes: Andernfalls können Sie einfach zur Implementierung scrollen .

Aufrufstapelgröße und rekursive Programmierung (Dungeon-Analogie)

Den Schatz finden und gehen

Stellen Sie sich vor, Sie betreten einen riesigen Kerker mit nummerierten Räumen und suchen nach einem Schatz. Sie kennen den Ort nicht, haben aber einige Hinweise, wie Sie den Schatz finden können. Jede Anzeige ist ein Rätsel (Schwierigkeitsgrad variiert, aber Sie können nicht vorhersagen, wie schwer sie sein werden). Sie beschließen, ein wenig über eine Strategie nachzudenken, um Zeit zu sparen, und machen zwei Beobachtungen:

  1. Es ist schwierig (lang), den Schatz zu finden, da Sie (möglicherweise schwierige) Rätsel lösen müssen, um dorthin zu gelangen.
  2. Sobald der Schatz gefunden wurde, kann es einfach sein, zum Eingang zurückzukehren. Sie müssen nur denselben Pfad in die andere Richtung verwenden (obwohl dies ein wenig Speicher benötigt, um sich an Ihren Pfad zu erinnern).

Wenn Sie den Dungeon betreten, sehen Sie hier ein kleines Notizbuch . Sie beschließen, damit jeden Raum aufzuschreiben, den Sie nach dem Lösen eines Rätsels verlassen (wenn Sie einen neuen Raum betreten). Auf diese Weise können Sie zum Eingang zurückkehren. Das ist eine geniale Idee, Sie werden nicht einmal einen Cent für die Umsetzung Ihrer Strategie ausgeben .

Sie betreten den Dungeon und lösen mit großem Erfolg die ersten 1001 Rätsel, aber hier kommt etwas, das Sie nicht geplant hatten. Sie haben keinen Platz mehr in dem Notizbuch, das Sie ausgeliehen haben. Sie beschließen , Ihre Suche abzubrechen, da Sie es vorziehen, den Schatz nicht zu haben, als für immer im Dungeon verloren zu sein (das sieht in der Tat klug aus).

Ausführen eines rekursiven Programms

Im Grunde ist es genau das Gleiche wie den Schatz zu finden. Der Dungeon ist der Speicher des Computers . Ihr Ziel ist es nun nicht, einen Schatz zu finden, sondern eine Funktion zu berechnen (finden Sie f (x) für ein gegebenes x ). Die Angaben sind einfach Unterprogramme, die Ihnen beim Lösen von f (x) helfen . Ihre Strategie ist dieselbe wie die Call-Stack- Strategie, das Notebook ist der Stack, die Räume sind die Rücksprungadressen der Funktionen:

x = ["over here", "am", "I"]
y = sorted(x) # You're about to enter a room named `sorted`, note down the current room address here so you can return back: 0x4004f4 (that room address looks weird)
# Seems like you went back from your quest using the return address 0x4004f4
# Let's see what you've collected 
print(' '.join(y))

Das Problem, auf das Sie im Dungeon gestoßen sind, ist hier dasselbe. Der Aufrufstapel hat eine endliche Größe (hier 1000). Wenn Sie also zu viele Funktionen eingeben, ohne zurückzukehren, füllen Sie den Aufrufstapel und haben einen Fehler, der aussieht wie "Lieber Abenteurer, es tut mir sehr leid, aber dein Notizbuch ist voll" : das ruft sich einmal auf - immer und immer wieder -) du wirst immer wieder eingeben, bis die Berechnung abgeschlossen ist (bis der Schatz gefunden ist) und von zurückkehren bis Sie zu dem Ort zurückkehren, an dem Sie zuerst angerufen haben. Der Aufrufstapel wird bis zum Ende, an dem er nacheinander von allen Rücksprungadressen befreit wird, niemals von irgendetwas befreit.RecursionError: maximum recursion depth exceeded . Beachten Sie, dass Sie keine Rekursion benötigen, um den Aufrufstapel zu füllen. Es ist jedoch sehr unwahrscheinlich, dass ein nicht rekursiver Programmaufruf 1000 funktioniert, ohne jemals zurückzukehren. Es ist auch wichtig zu verstehen, dass nach der Rückkehr von einer Funktion der Aufrufstapel von der verwendeten Adresse befreit wird (daher der Name "Stapel", die Rücksprungadresse wird vor der Eingabe einer Funktion eingegeben und bei der Rückkehr herausgezogen). Im Sonderfall einer einfachen Rekursion (eine Funktionffff

Wie vermeide ich dieses Problem?

Das ist eigentlich ziemlich einfach: "Verwenden Sie keine Rekursion, wenn Sie nicht wissen, wie tief sie gehen kann". Dies ist nicht immer der Fall, da in einigen Fällen die Tail Call-Rekursion optimiert werden kann (TCO) . In Python ist dies jedoch nicht der Fall, und selbst eine "gut geschriebene" rekursive Funktion optimiert die Stapelverwendung nicht . Zu dieser Frage gibt es einen interessanten Beitrag von Guido: Eliminierung der Schwanzrekursion .

Es gibt eine Technik, mit der Sie jede rekursive Funktion iterativ machen können. Diese Technik können wir als Ihr eigenes Notizbuch bezeichnen . In unserem speziellen Fall untersuchen wir beispielsweise einfach eine Liste. Das Betreten eines Raums entspricht dem Eingeben einer Unterliste. Die Frage, die Sie sich stellen sollten, lautet: Wie kann ich von einer Liste zu ihrer übergeordneten Liste zurückkehren? Die Antwort ist nicht so komplex. Wiederholen Sie Folgendes, bis das stackleer ist:

  1. Drücken Sie die aktuelle Liste addressund indexin a, stackwenn Sie eine neue Unterliste eingeben (beachten Sie, dass eine Listenadresse + ein Index auch eine Adresse ist, daher verwenden wir genau die gleiche Technik, die vom Aufrufstapel verwendet wird).
  2. Jedes Mal, wenn ein Element gefunden wird, wird yieldes angezeigt (oder in eine Liste aufgenommen).
  3. Sobald eine Liste vollständig durchsucht ist, stack kehren Sieaddressindex mit return (und ) zur übergeordneten Liste zurück .

Beachten Sie auch, dass dies einer DFS in einem Baum entspricht, in dem einige Knoten Unterlisten A = [1, 2]und andere einfache Elemente sind: 0, 1, 2, 3, 4(für L = [0, [1,2], 3, 4]). Der Baum sieht so aus:

                    L
                    |
           -------------------
           |     |     |     |
           0   --A--   3     4
               |   |
               1   2

Die Vorbestellung für die DFS-Durchquerung lautet: L, 0, A, 1, 2, 3, 4. Denken Sie daran, dass Sie zur Implementierung einer iterativen DFS auch einen Stapel "benötigen". Die Implementierung, die ich zuvor vorgeschlagen habe, führt zu folgenden Zuständen (für die stackund die flat_list):

init.:  stack=[(L, 0)]
**0**:  stack=[(L, 0)],         flat_list=[0]
**A**:  stack=[(L, 1), (A, 0)], flat_list=[0]
**1**:  stack=[(L, 1), (A, 0)], flat_list=[0, 1]
**2**:  stack=[(L, 1), (A, 1)], flat_list=[0, 1, 2]
**3**:  stack=[(L, 2)],         flat_list=[0, 1, 2, 3]
**3**:  stack=[(L, 3)],         flat_list=[0, 1, 2, 3, 4]
return: stack=[],               flat_list=[0, 1, 2, 3, 4]

In diesem Beispiel beträgt die maximale Größe des Stapels 2, da die Eingabeliste (und damit der Baum) die Tiefe 2 haben.

Implementierung

Für die Implementierung können Sie in Python ein wenig vereinfachen, indem Sie Iteratoren anstelle einfacher Listen verwenden. Verweise auf die (Unter-) Iteratoren werden zum Speichern von Unterlisten-Rücksprungadressen verwendet (anstatt sowohl die Listenadresse als auch den Index zu haben). Dies ist kein großer Unterschied, aber ich denke, dies ist besser lesbar (und auch etwas schneller):

def flatten(iterable):
    return list(items_from(iterable))

def items_from(iterable):
    cursor_stack = [iter(iterable)]
    while cursor_stack:
        sub_iterable = cursor_stack[-1]
        try:
            item = next(sub_iterable)
        except StopIteration:   # post-order
            cursor_stack.pop()
            continue
        if is_list_like(item):  # pre-order
            cursor_stack.append(iter(item))
        elif item is not None:
            yield item          # in-order

def is_list_like(item):
    return isinstance(item, list)

Beachten Sie auch, dass is_list_likeich in I have isinstance(item, list), das geändert werden könnte, um mehr Eingabetypen zu verarbeiten, hier nur die einfachste Version haben wollte, in der (iterable) nur eine Liste ist. Das können Sie aber auch tun:

def is_list_like(item):
    try:
        iter(item)
        return not isinstance(item, str)  # strings are not lists (hmm...) 
    except TypeError:
        return False

Dies betrachtet Zeichenfolgen als "einfache Elemente" und wird daher flatten_iter([["test", "a"], "b])zurückgegeben ["test", "a", "b"]und nicht ["t", "e", "s", "t", "a", "b"]. Beachten Sie, dass in diesem Fall iter(item)jedes Element zweimal aufgerufen wird. Stellen Sie sich vor, es sei eine Übung für den Leser, dies sauberer zu machen.

Tests und Anmerkungen zu anderen Implementierungen

Denken Sie am Ende daran, dass Sie eine unendlich verschachtelte Liste nicht mit drucken können L, print(L)da intern rekursive Aufrufe von __repr__( RecursionError: maximum recursion depth exceeded while getting the repr of an object) verwendet werden. Aus dem gleichen Grund flattenschlagen Lösungen für das Einbeziehen strmit derselben Fehlermeldung fehl.

Wenn Sie Ihre Lösung testen müssen, können Sie mit dieser Funktion eine einfache verschachtelte Liste erstellen:

def build_deep_list(depth):
    """Returns a list of the form $l_{depth} = [depth-1, l_{depth-1}]$
    with $depth > 1$ and $l_0 = [0]$.
    """
    sub_list = [0]
    for d in range(1, depth):
        sub_list = [d, sub_list]
    return sub_list

Welches gibt: build_deep_list(5)>>> [4, [3, [2, [1, [0]]]]].

cglacet
quelle
2

Hier ist die compiler.ast.flattenImplementierung in 2.7.5:

def flatten(seq):
    l = []
    for elt in seq:
        t = type(elt)
        if t is tuple or t is list:
            for elt2 in flatten(elt):
                l.append(elt2)
        else:
            l.append(elt)
    return l

Es gibt bessere und schnellere Methoden (Wenn Sie hier angekommen sind, haben Sie sie bereits gesehen)

Beachten Sie auch:

Veraltet seit Version 2.6: Das Compiler-Paket wurde in Python 3 entfernt.

pradyunsg
quelle
2

total hacky aber ich denke es würde funktionieren (abhängig von deinem data_type)

flat_list = ast.literal_eval("[%s]"%re.sub("[\[\]]","",str(the_list)))
Joran Beasley
quelle
2

Verwenden Sie einfach eine funcyBibliothek: pip install funcy

import funcy


funcy.flatten([[[[1, 1], 1], 2], 3]) # returns generator
funcy.lflatten([[[[1, 1], 1], 2], 3]) # returns list
ADR
quelle
1
Zu Ihrer Information: Es verwendet eine rekursive Lösung: Link zur Quelle
Georgy
1

Hier ist ein weiterer py2-Ansatz. Ich bin mir nicht sicher, ob er der schnellste, eleganteste oder sicherste ist.

from collections import Iterable
from itertools import imap, repeat, chain


def flat(seqs, ignore=(int, long, float, basestring)):
    return repeat(seqs, 1) if any(imap(isinstance, repeat(seqs), ignore)) or not isinstance(seqs, Iterable) else chain.from_iterable(imap(flat, seqs))

Es kann jeden bestimmten (oder abgeleiteten) Typ ignorieren, den Sie möchten. Es gibt einen Iterator zurück, sodass Sie ihn in einen bestimmten Container wie Liste, Tupel, Diktat konvertieren oder einfach verbrauchen können, um den Speicherbedarf zum Guten oder Schlechten zu verringern Es kann anfängliche nicht iterierbare Objekte wie int ...

Beachten Sie, dass der Großteil des schweren Hebens in C ausgeführt wird, da meines Wissens so itertools implementiert sind. AFAIK ist also zwar rekursiv, AFAIK jedoch nicht an die Python-Rekursionstiefe gebunden, da die Funktionsaufrufe in C ausgeführt werden bedeutet nicht, dass Sie an Speicher gebunden sind, insbesondere in OS X, wo die Stapelgröße ab heute eine harte Grenze hat (OS X Mavericks) ...

Es gibt einen etwas schnelleren Ansatz, aber eine weniger portable Methode. Verwenden Sie diese Methode nur, wenn Sie davon ausgehen können, dass die Basiselemente der Eingabe explizit bestimmt werden können. Andernfalls erhalten Sie eine unendliche Rekursion, und OS X mit seiner begrenzten Stapelgröße wird dies tun Wirf ziemlich schnell einen Segmentierungsfehler ...

def flat(seqs, ignore={int, long, float, str, unicode}):
    return repeat(seqs, 1) if type(seqs) in ignore or not isinstance(seqs, Iterable) else chain.from_iterable(imap(flat, seqs))

Hier verwenden wir Mengen, um nach dem Typ zu suchen, sodass O (1) gegen O (Anzahl der Typen) benötigt wird, um zu prüfen, ob ein Element ignoriert werden soll oder nicht, obwohl natürlich jeder Wert mit dem abgeleiteten Typ der angegebenen ignorierten Typen fehlschlägt , deshalb wird es verwendet str, unicodealso mit Vorsicht verwenden ...

Tests:

import random

def test_flat(test_size=2000):
    def increase_depth(value, depth=1):
        for func in xrange(depth):
            value = repeat(value, 1)
        return value

    def random_sub_chaining(nested_values):
        for values in nested_values:
            yield chain((values,), chain.from_iterable(imap(next, repeat(nested_values, random.randint(1, 10)))))

    expected_values = zip(xrange(test_size), imap(str, xrange(test_size)))
    nested_values = random_sub_chaining((increase_depth(value, depth) for depth, value in enumerate(expected_values)))
    assert not any(imap(cmp, chain.from_iterable(expected_values), flat(chain(((),), nested_values, ((),)))))

>>> test_flat()
>>> list(flat([[[1, 2, 3], [4, 5]], 6]))
[1, 2, 3, 4, 5, 6]
>>>  

$ uname -a
Darwin Samys-MacBook-Pro.local 13.3.0 Darwin Kernel Version 13.3.0: Tue Jun  3 21:27:35 PDT 2014; root:xnu-2422.110.17~1/RELEASE_X86_64 x86_64
$ python --version
Python 2.7.5
Samy Vilar
quelle
1

Ohne Bibliothek zu benutzen:

def flat(l):
    def _flat(l, r):    
        if type(l) is not list:
            r.append(l)
        else:
            for i in l:
                r = r + flat(i)
        return r
    return _flat(l, [])



# example
test = [[1], [[2]], [3], [['a','b','c'] , [['z','x','y']], ['d','f','g']], 4]    
print flat(test) # prints [1, 2, 3, 'a', 'b', 'c', 'z', 'x', 'y', 'd', 'f', 'g', 4]
Alfasin
quelle
1

Verwenden von itertools.chain:

import itertools
from collections import Iterable

def list_flatten(lst):
    flat_lst = []
    for item in itertools.chain(lst):
        if isinstance(item, Iterable):
            item = list_flatten(item)
            flat_lst.extend(item)
        else:
            flat_lst.append(item)
    return flat_lst

Oder ohne Verkettung:

def flatten(q, final):
    if not q:
        return
    if isinstance(q, list):
        if not isinstance(q[0], list):
            final.append(q[0])
        else:
            flatten(q[0], final)
        flatten(q[1:], final)
    else:
        final.append(q)
Saksham Varma
quelle
1

Ich habe rekursiv verwendet, um verschachtelte Listen mit beliebiger Tiefe zu lösen

def combine_nlist(nlist,init=0,combiner=lambda x,y: x+y):
    '''
    apply function: combiner to a nested list element by element(treated as flatten list)
    '''
    current_value=init
    for each_item in nlist:
        if isinstance(each_item,list):
            current_value =combine_nlist(each_item,current_value,combiner)
        else:
            current_value = combiner(current_value,each_item)
    return current_value

Nachdem ich die Funktion combin_nlist definiert habe, ist es einfach, diese Funktion zum Abflachen zu verwenden. Oder Sie können es in einer Funktion kombinieren. Ich mag meine Lösung, weil sie auf jede verschachtelte Liste angewendet werden kann.

def flatten_nlist(nlist):
    return combine_nlist(nlist,[],lambda x,y:x+[y])

Ergebnis

In [379]: flatten_nlist([1,2,3,[4,5],[6],[[[7],8],9],10])
Out[379]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Oldyoung
quelle
"verschachtelte Liste mit beliebiger Tiefe" nicht wahr. Versuchen Sie einfach, Sie werden sehen: current_value = combiner(current_value,each_item) RecursionError: maximum recursion depth exceeded
cglacet
hmmm ich versuche du liste mit mehr als 1000 schichten zu flaten?
Oldyoung
Das ist natürlich der springende Punkt der Diskussion über rekursive und iterative Lösungen. Wenn Sie im Voraus wissen, dass die Anzahl der Schichten <als 1000 ist, funktioniert die einfachste Lösung. Wenn Sie "jede Tiefe" sagen, schließt dies eine Liste mit einer Tiefe> 1000 ein.
cglacet
1

Am einfachsten ist es, die Morph- Bibliothek mit zu verwenden pip install morph.

Der Code lautet:

import morph

list = [[[1, 2, 3], [4, 5]], 6]
flattened_list = morph.flatten(list)  # returns [1, 2, 3, 4, 5, 6]
YPCrumble
quelle
1

Ich bin mir bewusst, dass es bereits viele großartige Antworten gibt, aber ich wollte eine Antwort hinzufügen, die die funktionale Programmiermethode zur Lösung der Frage verwendet. In dieser Antwort verwende ich die doppelte Rekursion:

def flatten_list(seq):
    if not seq:
        return []
    elif isinstance(seq[0],list):
        return (flatten_list(seq[0])+flatten_list(seq[1:]))
    else:
        return [seq[0]]+flatten_list(seq[1:])

print(flatten_list([1,2,[3,[4],5],[6,7]]))

Ausgabe:

[1, 2, 3, 4, 5, 6, 7]
Leo Wahyd
quelle
1

Ich bin mir nicht sicher, ob dies notwendigerweise schneller oder effektiver ist, aber das mache ich:

def flatten(lst):
    return eval('[' + str(lst).replace('[', '').replace(']', '') + ']')

L = [[[1, 2, 3], [4, 5]], 6]
print(flatten(L))

Die flattenFunktion hier verwandelt die Liste in eine Zeichenfolge, entfernt alle eckigen Klammern , bringt eckige Klammern wieder an den Enden an und wandelt sie wieder in eine Liste um.

Wenn Sie jedoch wüssten, dass Ihre Liste eckige Klammern in Zeichenfolgen enthält, [[1, 2], "[3, 4] and [5]"]müssten Sie etwas anderes tun.

Diligar
quelle
Dies hat keinen Vorteil gegenüber der einfachen Lösung, da hierdurch keine tiefen Listen verarbeitet werden können, dh "RecursionError: Maximale Rekursionstiefe überschritten, während die Repräsentation eines Objekts abgerufen wird".
Cglacet
1

Dies ist eine einfache Implementierung von flatten auf python2

flatten=lambda l: reduce(lambda x,y:x+y,map(flatten,l),[]) if isinstance(l,list) else [l]

test=[[1,2,3,[3,4,5],[6,7,[8,9,[10,[11,[12,13,14]]]]]],]
print flatten(test)

#output [1, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
Statham
quelle
1

Dadurch wird eine Liste oder ein Wörterbuch (oder eine Liste von Listen oder Wörterbüchern von Wörterbüchern usw.) abgeflacht. Es wird davon ausgegangen, dass die Werte Zeichenfolgen sind, und es wird eine Zeichenfolge erstellt, die jedes Element mit einem Trennzeichen verknüpft. Wenn Sie möchten, können Sie das Ergebnis anschließend mit dem Trennzeichen in ein Listenobjekt aufteilen. Es verwendet die Rekursion, wenn der nächste Wert eine Liste oder eine Zeichenfolge ist. Verwenden Sie das Schlüsselargument, um festzustellen, ob Sie die Schlüssel oder die Werte (setzen Sie den Schlüssel auf false) aus dem Wörterbuchobjekt möchten.

def flatten_obj(n_obj, key=True, my_sep=''):
    my_string = ''
    if type(n_obj) == list:
        for val in n_obj:
            my_sep_setter = my_sep if my_string != '' else ''
            if type(val) == list or type(val) == dict:
                my_string += my_sep_setter + flatten_obj(val, key, my_sep)
            else:
                my_string += my_sep_setter + val
    elif type(n_obj) == dict:
        for k, v in n_obj.items():
            my_sep_setter = my_sep if my_string != '' else ''
            d_val = k if key else v
            if type(v) == list or type(v) == dict:
                my_string += my_sep_setter + flatten_obj(v, key, my_sep)
            else:
                my_string += my_sep_setter + d_val
    elif type(n_obj) == str:
        my_sep_setter = my_sep if my_string != '' else ''
        my_string += my_sep_setter + n_obj
        return my_string
    return my_string

print(flatten_obj(['just', 'a', ['test', 'to', 'try'], 'right', 'now', ['or', 'later', 'today'],
                [{'dictionary_test': 'test'}, {'dictionary_test_two': 'later_today'}, 'my power is 9000']], my_sep=', ')

Ausbeuten:

just, a, test, to, try, right, now, or, later, today, dictionary_test, dictionary_test_two, my power is 9000
Matt Farguson
quelle
0

Wenn Sie Rekursion mögen, könnte dies eine für Sie interessante Lösung sein:

def f(E):
    if E==[]: 
        return []
    elif type(E) != list: 
        return [E]
    else:
        a = f(E[0])
        b = f(E[1:])
        a.extend(b)
        return a

Ich habe dies tatsächlich aus einem Übungsschema-Code übernommen, den ich vor einiger Zeit geschrieben hatte.

Genießen!

inspectorG4dget
quelle
0

Ich bin neu in Python und komme aus einem lisp Hintergrund. Folgendes habe ich mir ausgedacht (siehe die Variablennamen für lulz):

def flatten(lst):
    if lst:
        car,*cdr=lst
        if isinstance(car,(list,tuple)):
            if cdr: return flatten(car) + flatten(cdr)
            return flatten(car)
        if cdr: return [car] + flatten(cdr)
        return [car]

Scheint zu funktionieren. Prüfung:

flatten((1,2,3,(4,5,6,(7,8,(((1,2)))))))

kehrt zurück:

[1, 2, 3, 4, 5, 6, 7, 8, 1, 2]
Michael Puckett
quelle