568 Stimmen

Eine unregelmäßige Liste von Listen abflachen

Ja, ich weiß, dass dieses Thema schon einmal behandelt wurde ( aquí , aquí , aquí , aquí ), aber soweit ich weiß, scheitern alle Lösungen, außer einer, an einer solchen Liste:

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

Die gewünschte Leistung ist

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

Oder vielleicht noch besser, ein Iterator. Die einzige Lösung, die ich gesehen habe, die für eine beliebige Verschachtelung funktioniert, ist gefunden in dieser 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 dies das beste Modell? Habe ich etwas übersehen? Gibt es Probleme?

484voto

Cristian Punkte 40446

Die Verwendung von Generatorfunktionen kann Ihr Beispiel leichter lesbar machen und die Leistung verbessern.

Python 2

Die Verwendung des Iterable ABC hinzugefügt in 2.6:

from collections import Iterable

def flatten(xs):
    for x in xs:
        if isinstance(x, Iterable) and not isinstance(x, basestring):
            for item in flatten(x):
                yield item
        else:
            yield x

Python 3

In Python 3, basestring ist nicht mehr, aber das Tupel (str, bytes) hat die gleiche Wirkung. Auch die yield from Operator gibt ein Element aus einem Generator nacheinander zurück.

from collections.abc import Iterable

def flatten(xs):
    for x in xs:
        if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
            yield from flatten(x)
        else:
            yield x

68voto

Josh Lee Punkte 159535

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]

Etwas knapper, aber im Wesentlichen dasselbe.

49voto

dansalmo Punkte 10858

Generator mit Rekursion und Duck-Typing (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]

47voto

samplebias Punkte 35688

Hier ist meine funktionale Version von rekursivem Flatten, die sowohl Tupel als auch Listen behandelt, und Sie können eine beliebige Mischung von Positionsargumenten einfügen. Gibt einen Generator zurück, der die gesamte Sequenz der Reihe nach erzeugt, Argument für Argument:

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

Verwendung:

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]

35voto

Alex Martelli Punkte 805329

Generator-Version der nicht-rekursiven Lösung von @unutbu, wie von @Andrew in einem Kommentar gefordert:

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)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X