505

はい、私はこの主題が以前にカバーされたことを知っています (ここここここここ) が、私の知る限り、1 つを除いてすべての解決策は次のようなリストで失敗します:

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

目的の出力がある場所

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

または、イテレータの方がよいかもしれません。任意のネスティングで機能する唯一の解決策は、この質問にあります。

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)

これは最高のモデルですか?私は何かを見落としましたか?問題はありますか?

4

48 に答える 48

438

ジェネレーター関数を使用すると、例が少し読みやすくなり、おそらくパフォーマンスが向上します。

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

2.6で追加されたIterableABCを使用しました。

Python 3

Python 3では、basestringこれ以上ではありませんが、とのタプルを使用して、strそこでbytes同じ効果を得ることができます。

オペレーターはyield from、ジェネレーターからアイテムを一度に1つずつ返します。サブジェネレータに委任するためのこの構文は、3.3で追加されました。

from collections.abc import Iterable

def flatten(l):
    for el in l:
        if isinstance(el, Iterable) and not isinstance(el, (str, bytes)):
            yield from flatten(el)
        else:
            yield el
于 2010-01-28T22:35:51.903 に答える
60

私の解決策:

import collections


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

もう少し簡潔ですが、ほとんど同じです。

于 2010-01-28T22:34:45.500 に答える
44

再帰とダックタイピングを使用するジェネレーター (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]
于 2013-01-23T23:04:43.250 に答える
38

これは、タプルとリストの両方を処理し、位置引数の任意の組み合わせをスローできる再帰的フラット化の機能的なバージョンです。arg ごとに順番にシーケンス全体を生成するジェネレータを返します。

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

使用法:

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]
于 2011-03-23T17:42:24.403 に答える
36

@Andrew がコメントで要求した、@unutbu の非再帰的ソリューションのジェネレーター バージョン:

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

このジェネレーターの少し簡略化されたバージョン:

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)
于 2010-01-29T00:27:22.303 に答える
31

このバージョンの はflatten、python の再帰制限を回避します (したがって、任意の深さのネストされた iterable で動作します)。これは、文字列と任意の iterable (無限のものも含む) を処理できるジェネレーターです。

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

以下に、その使用法を示すいくつかの例を示します。

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]

無限のジェネレーターを処理できますがflatten、無限のネストを処理できません。

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

print(list(IT.islice(flatten(infinitely_nested()), 10)))
# hangs
于 2010-01-28T22:42:07.743 に答える
12
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
于 2011-01-04T04:29:07.627 に答える
12

さらに興味深い別の答えがあります...

import re

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

    return(d)

基本的に、ネストされたリストを文字列に変換し、正規表現を使用してネストされた構文を取り除き、結果を (フラット化された) リストに変換します。

于 2011-01-14T18:31:33.077 に答える
6

エレガントで非常にパイソン的な答えが選択されていますが、私はレビューのためだけに私の解決策を提示します:

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

このコードの良し悪しを教えてください。

于 2011-03-07T22:32:07.433 に答える
6

これは、任意の深さのリストを平坦化する単純な関数です。スタック オーバーフローを避けるため、再帰はありません。

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
于 2013-12-10T12:56:51.233 に答える
4

ここですでに利用可能なすべての回答を調べたわけではありませんが、最初と残りのリスト処理のLispの方法から借りて、私が思いついた1つのライナーを次に示します

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

ここに単純なケースとそれほど単純ではないケースがあります -

>>> 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]
>>> 
于 2016-04-08T13:24:02.847 に答える
4

私はシンプルな答えを好みます。発電機はありません。再帰または再帰の制限はありません。ただの繰り返し:

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

これは、内側の for ループと外側の while ループの 2 つのリストで機能します。

内側の for ループは、リストを反復処理します。リスト要素が見つかった場合、(1) list.extend() を使用してその部分の 1 レベルのネストを平坦化し、(2) keepChecking を True に切り替えます。keepchecking は、外側の while ループを制御するために使用されます。外側のループが true に設定されると、別のパスの内側のループがトリガーされます。

これらのパスは、ネストされたリストが見つからなくなるまで発生し続けます。何も見つからないパスが最終的に発生すると、keepChecking が true にトリップされることはありません。つまり、listIsNested は false のままで、外側の while ループが終了します。

その後、平坦化されたリストが返されます。

テスト走行

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

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

于 2011-01-13T03:19:39.887 に答える
2

compiler.ast.flatten2.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

より優れた、より高速な方法があります (ここにたどり着いた場合は、既にそれらを見たことがあるでしょう)。

また、次の点に注意してください。

バージョン 2.6 以降非推奨: コンパイラ パッケージは Python 3 で削除されました。

于 2013-08-27T13:05:57.553 に答える
2

完全にハックですが、うまくいくと思います(data_typeによって異なります)

flat_list = ast.literal_eval("[%s]"%re.sub("[\[\]]","",str(the_list)))
于 2014-05-28T17:54:20.563 に答える
1

ここに投稿されたようなものは見当たらず、同じ件名の閉じられた質問からここにたどり着きましたが、このようなことをしてみませんか(分割したいリストのタイプがわかっている場合):

>>> a = [1, 2, 3, 5, 10, [1, 25, 11, [1, 0]]]    
>>> g = str(a).replace('[', '').replace(']', '')    
>>> b = [int(x) for x in g.split(',') if x.strip()]

要素のタイプを知る必要がありますが、これは一般化できると思います。速度の点では、より高速になると思います。

于 2011-08-12T08:51:28.970 に答える
1

これが別のpy2アプローチです。それが最速か、最もエレガントで安全かはわかりません...

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

必要な特定の (または派生した) 型を無視し、イテレータを返すため、リスト、タプル、dict などの特定のコンテナーに変換するか、単に消費してメモリ フットプリントを減らすことができます。 int ... などの初期の反復不可能なオブジェクトを処理できます。

私が知る限り、 itertools がどのように実装されているかを知っている限り、重労働のほとんどはCで行われることに注意してください.特に、今日の時点でスタックサイズにハードリミットがあるOS X(OS X Mavericks)では、メモリに制限されているという意味ではありません...

少し高速なアプローチがありますが、移植性の低い方法です。入力の基本要素を明示的に決定できると想定できる場合にのみ使用してください。それ以外の場合は無限再帰が得られ、スタックサイズが制限されている OS X はセグメンテーション違反をかなり迅速にスローします...

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

ここでは、セットを使用して型をチェックしているため、要素を無視する必要があるかどうかを確認するには、O(1) 対 O(型の数) が必要ですが、もちろん、指定された無視された型の派生型を持つ値はすべて失敗します。 、これが を使用する理由なのでstrunicode注意して使用してください...

テスト:

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
于 2014-08-17T19:52:51.253 に答える
1

すでに多くの素晴らしい回答があることは承知していますが、質問を解決する関数型プログラミング手法を使用する回答を追加したかったのです。この回答では、二重再帰を利用しています:

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

出力:

[1, 2, 3, 4, 5, 6, 7]
于 2016-10-03T15:46:27.637 に答える
1

私は愚かな男なので、「愚かな」解決策を提供します。そのすべての再帰は私の脳を傷つけます。

flattened_list = []
nested_list = [[[1, 2, 3], [4, 5]], 6]

def flatten(nested_list, container):
    for item in nested_list:
        if isintance(item, list):
            flatten(item, container)
        else:
            container.append(item)

>>> flatten(nested_list, flattened_list)
>>> flattened_list
[1, 2, 3, 4, 5, 6]

私はそれが副作用を使用していることを理解していますが、それは私の再帰の理解の範囲内です

于 2016-04-04T20:38:15.663 に答える
1

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

または連鎖なし:

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)
于 2015-02-27T02:38:33.637 に答える
0

私はPythonを初めて使用し、Lispのバックグラウンドを持っています。これは私が思いついたものです(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]

動作しているようです。テスト:

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

戻り値:

[1, 2, 3, 4, 5, 6, 7, 8, 1, 2]
于 2010-12-20T23:24:37.670 に答える
0

別の質問に対する私自身の回答から恥知らずに取られました。

この機能

  • を使用しません。isinstanceこれは悪であり、ダック タイピングを妨害するためです。
  • reduce再帰的に使用します。を使った答えがなければなりませんreduce
  • 要素がネストされたリスト、ネストされていないアトムのリスト、またはアトム (再帰制限に従う) のいずれかである、任意のネストされたリストで動作します。
  • LBYL を実行しません。
  • ただし、文字列をアトムとして含むネストされたリストではそうではありません。

以下のコード:

def flattener(left, right):
    try:
        res = reduce(flattener, right, left)
    except TypeError:
        left.append(right)
        res = left
    return res


def flatten(seq):
    return reduce(flattener, seq, [])


>>> nested_list = [0, [1], [[[[2]]]],
                   [3, [], [4, 5]],
                   [6, [7, 8],
                    9, [[[]], 10,
                        []]],
                   11, [], [],
                   [12]]
>>> flatten(nested_list)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
于 2015-10-13T22:41:14.323 に答える
0

再帰が好きなら、これはあなたにとって興味深い解決策かもしれません:

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

これは、私が以前に書いた練習用の Scheme コードから実際に採用したものです。

楽しみ!

于 2010-01-31T00:19:36.413 に答える
0

iteration-utilitiesこのソリューションは、python のライブラリとその機能に基づいています。 deepflatten

from iteration_utilities import deepflatten
list(deepflatten(test))
于 2021-07-05T13:25:06.817 に答える
0
def nested_list(depth):
    l = [depth]
    for i in range(depth-1, 0, -1):
        l = [i, l]
    return l

nested_list(10)

[1, [2, [3, [4, [5, [6, [7, [8, [9, [10]]]]]]]]]]

def Flatten(ul):
    fl = []
    for i in ul:
        if type(i) is list:
            fl += Flatten(i)
        else:
            fl += [i]
    return fl

Flatten(nested_list(10))

[1、2、3、4、5、6、7、8、9、10]

ベンチマーク

l = nested_list(100)

https://stackoverflow.com/a/2158532

コレクションのインポート

デフフラット(l):
    l の el の場合:
        isinstance(el, collections.Iterable) で isinstance(el, (str, bytes)) でない場合:
            flatten(el) からの利回り
        そうしないと:
            イールドエル
%%timeit -n 1000
list(flatten(l))

ループあたり 320 μs ± 14.3 μs (7 回の実行の平均 ± 標準偏差、各 1000 ループ)

%%timeit -n 1000
Flatten(l)

ループあたり 60 µs ± 10.2 µs (7 回の実行の平均 ± 標準偏差、各 1000 ループ)

list(flatten(l)) == Flatten(l)

真実

于 2019-10-18T14:10:28.020 に答える
0
def flatten(item) -> list:
    if not isinstance(item, list): return item
    return reduce(lambda x, y: x + [y] if not isinstance(y, list) else x + [*flatten(y)], item, [])

二行削減機能。

于 2019-12-04T18:42:33.273 に答える
0

Python の「type」関数を使用することもできます。リストを反復するとき、アイテムがリストかどうかをチェックします。そうでない場合は「追加」し、そうでない場合は「拡張」します。ここにサンプルコードがあります -

l=[1,2,[3,4],5,[6,7,8]]
x=[]
for i in l:
    if type(i) is list:
        x.extend(i)
    else:
        x.append(i)
print x

出力:

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

append() と extend() の詳細については、この Web サイトを確認してください: https://docs.python.org/2/tutorial/datastructures.html

于 2016-03-22T13:55:38.013 に答える
-1

以下はおそらくpython 3で機能すると思います:

def get_flat_iter(xparent):
    try:
        r = xparent
        if hasattr(xx, '__iter__'):
            iparent = iter(xparent)
            if iparent != xparent:
                r = map(a, xparent)
    finally:
         pass
    return r

irregular_list = [1, [2, [3, 4]]]
flat_list = list(irregular_list)
print(flat_list) # [1, 2, 3, 4]
于 2019-10-25T18:06:39.263 に答える
-2
L2 = [o for k in [[j] if not isinstance(j,list) else j for j in [k for i in [[m] if not 
isinstance(m,list) else m for m in L] for k in i]] for o in k]
于 2013-07-02T13:59:14.033 に答える