リストのリストからフラットリストを作成する方法は?


3374

Pythonのリストのリストから単純なリストを作成するショートカットはあるのでしょうか。

forループでそれを行うことができますが、いくつかのクールな「ワンライナー」があるのでしょうか?で試しましたreduce()が、エラーになります。

コード

l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
reduce(lambda x, y: x.extend(y), l)

エラーメッセージ

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
AttributeError: 'NoneType' object has no attribute 'extend'

20
これについての詳細な議論があります:rightfootin.blogspot.com/2006/09/more-on-python-flatten.html、リストの任意にネストされたリストを平坦化するいくつかの方法について議論します。おもしろい!
RichieHindle 2009年

6
他のいくつかの回答の方が優れていますが、失敗する理由は、 'extend'メソッドが常にNoneを返すためです。長さが2のリストの場合、機能しますがNoneを返します。より長いリストの場合、Noneを返す最初の2つの引数を消費します。その後、None.extend(<third arg>)が続くため、この
エラー

ここでは@ shawn-chinソリューションの方がPython的ですが、シーケンスタイプを保持する必要がある場合、リストのリストではなくタプルのタプルがあるとすると、reduce(operator.concat、tuple_of_tuples)を使用する必要があります。タプルでoperator.concatを使用すると、リストでchain.from_iterablesを実行するよりも高速に動作するようです。
Meitham 2014年

回答:


4796

リストのリストを考えるとl

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

つまり:

flat_list = []
for sublist in l:
    for item in sublist:
        flat_list.append(item)

これまでに投稿されたショートカットよりも高速です。(lはフラット化するリストです。)

これが対応する関数です:

flatten = lambda l: [item for sublist in l for item in sublist]

証拠としてtimeit、標準ライブラリのモジュールを使用できます。

$ 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

説明:(での+暗黙の使用を含む)に基づくショートカットsumは、O(L**2)Lサブリストがある場合に必要です-中間結果リストが長くなり続けるため、各ステップで新しい中間結果リストオブジェクトが割り当てられ、すべてのアイテム前の中間結果でコピーする必要があります(最後に追加されたいくつかの新しい結果も同様)。したがって、単純化のために、一般性を実際に失うことなく、それぞれにIアイテムのLサブリストがあるとします。最初のIアイテムはL-1回、2番目のIアイテムはL-2回、というようにコピーされます。コピーの総数は、1からLまでのxのxの合計のI倍I * (L**2)/2です。つまり、です。

リスト内包は、1つのリストを1回だけ生成し、各項目を(元の居住地から結果リストに)正確に1回だけコピーします。


486
私が使用して、同じデータでテストを試してみましたitertools.chain.from_iterable$ python -mtimeit -s'from itertools import chain; l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'list(chain.from_iterable(l))'。これは、ネストされたリスト内包表記の2倍以上の速さで実行されます。
2010年

274
入れ子になったforループとまったく同じように考えることができるまで、構文を理解するのは難しいと感じました。lのサブリストの場合:サブリストのアイテムの場合:利回りアイテム
Rob Crowell

23
@BorisChervenkov:list()イテレータをリストに実現するために呼び出しをラップしたことに注意してください。
2010年

163
[木の葉木の葉木の葉]は、理解しやすく、適用しやすいかもしれません。
John Mee

80
@ジョエル、実際には今日list(itertools.chain.from_iterable(l))が最高です-他のコメントとショーンの答えで気づかれたように。
Alex Martelli、2015年

1569

使用できますitertools.chain()

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

またはitertools.chain.from_iterable()*演算子を使用してリストを解凍する必要がないものを使用できます。

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

13
これ*は、chainリストの理解よりも簡単ではないトリッキーなことです。チェーンはパラメーターとして渡されたイテラブルのみを結合することを知っておく必要があります。*を指定すると、最上位のリストがパラメーターに展開されるためchain、これらのすべてのイテラブルを結合しますが、それ以上は降りません。これは、この場合のチェーンの使用よりも理解が読みやすくなると思います。
Tim Dierks、2014

52
@TimDierks:「これにはPython構文を理解する必要があります」が、Pythonで特定の手法を使用することに対する反論かどうかはわかりません。確かに、複雑な使用法は混乱する可能性がありますが、 "splat"演算子は一般に多くの状況で役立ちます。これは特に不明瞭な方法では使用していません。初心者には必ずしも明らかではないすべての言語機能を拒否すると、片方の手を後ろで縛っているということになります。リストの理解力が失われている間は、リスト内包表記を捨てることもできます。他のバックグラウンドのユーザーはfor、繰り返しappendがより明白なループを見つけるでしょう。
ShadowRanger 2015年

この回答、およびここでの他の回答は、トップレベルにも値が含まれている場合、誤った結果をもたらします。たとえば、list = [["abc","bcd"],["cde","def"],"efg"]出力は["abc", "bcd", "cde", "def", "e", "f", "g"].
gouravkr

そうです*、オペレータがpython2で使用することはできません
WKM

908

著者からの注記:これは非効率的です。しかし、モノイドは素晴らしいので、楽しいです。これは本番Pythonコードには適していません。

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

これは、最初の引数で渡されたイテラブルの要素を合計し、2番目の引数を合計の初期値として扱います(指定されていない0場合は代わりに使用され、この場合はエラーが発生します)。

ネストされたリストを加算しているので、あなたが実際に取得[1,3]+[2,4]した結果、sum([[1,3],[2,4]],[])に等しいです、[1,3,2,4]

リストのリストでのみ機能することに注意してください。リストのリストのリストについては、別のソリューションが必要になります。


100
それはかなりきちんとしていて賢いですが、読むのが混乱するので私はそれを使いません。
andrewrk

87
これは、画家のアルゴリズムjoelonsoftware.com/articles/fog0000000319.htmlであるShlemielです。
Mike Graham

44
リストの追加操作はを形成しますMonoid。これは+、一般的な意味での操作(数値のみに限定されない)を考えるための最も便利な抽象化の1つです。したがって、この答えは、リストをモノイドとして(正しい)処理するために私から+1するに値します。しかし、パフォーマンスは懸念されています...
ulidtko

7
@andrewrkええと、これが最もクリーンな方法だと考える人もいます:youtube.com/watch ?v=IOiZatlZtGU これがクールな理由を理解していない人は、誰もがこのようにするまで数十年待つ必要があります。 )発見されたが発明されていないプログラミング言語(および抽象化)を使用してみましょう。Monoidが発見されました。
jhegedus

11
合計が2次であるため、これは非常に非効率的な方法です。
ジャン=フランソワ・ファーブル

461

私はほとんどの提案されたソリューションをperfplot(私のペットプロジェクト、本質的にはラッパーtimeit)でテストし、

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

多数の小さなリストと少数の長いリストが連結されている場合の両方で、最速のソリューションになります。(operator.iadd同様に高速です。)

ここに画像の説明を入力してください

ここに画像の説明を入力してください


プロットを再現するコード:

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,
    # setup=lambda n: [list(range(n))] * 10,
    kernels=[
        forfor,
        sum_brackets,
        functools_reduce,
        functools_reduce_iconcat,
        itertools_chain,
        numpy_flat,
        numpy_concatenate,
    ],
    n_range=[2 ** k for k in range(16)],
    xlabel="num lists (of length 10)",
    # xlabel="len lists (10 lists total)"
)

25
巨大なネストされたリストの場合、「list(numpy.array(a).flat)」は上記のすべての関数の中で最速です。
Sara

正規表現を使用して試みました: 'list(map(int、re.findall(r "[\ w] +"、str(a))))'。速度はnumpy_concatenateより少し遅い
Justas

3-d perfplotを実行する方法はありますか?配列の平均サイズによる配列の数?
レオ

私はあなたの解決策が大好きです。短く、シンプルで効率的:-)
ShadyMBA

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

extend()例のメソッドはx、有用な値(reduce()期待値)を返す代わりに変更します。

reduceバージョンを実行するより速い方法は

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

19
reduce(operator.add, l)reduceバージョンを実行する正しい方法でしょう。ビルトインはラムダよりも高速です。
agf 2011

3
@agfは次のとおりです。* timeit.timeit('reduce(operator.add, l)', 'import operator; l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]', number=10000) 0.017956018447875977 * timeit.timeit('reduce(lambda x, y: x+y, l)', 'import operator; l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]', number=10000) 0.025218963623046875
lukmdo

8
これは、画家のアルゴリズムであるShlemielです。joelonsoftware.com/articles/fog0000000319.html
Mike Graham

2
これはにのみ使用できますintegers。しかし、リストに含まれている場合はstringどうなりますか?
Freddy

3
@Freddy:このoperator.add関数は、整数のリストと文字列のリストのどちらでも同じように機能します。
グレッグヒューギル2015

121

Djangoを使用する場合は、ホイールを再発明しないでください。

>>> from django.contrib.admin.utils import flatten
>>> l = [[1,2,3], [4,5], [6]]
>>> flatten(l)
>>> [1, 2, 3, 4, 5, 6]

... パンダ

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

... ユニパス

>>> from unipath.path import flatten
>>> list(flatten(l))

... Setuptools

>>> from setuptools.namespaces import flatten
>>> list(flatten(l))

4
flatten = itertools.chain.from_iterable正解である必要があります
geckos

3
すばらしい答えです!パンダの場合はl = [[[1、2、3]、[4、5]]、5]でも機能します
Markus Dutschke

1
私はパンダのソリューションが好きです。次のようなものがあればlist_of_menuitems = [1, 2, [3, [4, 5, [6]]]]、その結果はになります[1, 2, 3, 4, 5, 6]。私が見逃しているのは、平坦化されたレベルです。
imjoseangel

115

以下は、数値文字列ネストされたリスト、混合コンテナに適用される一般的なアプローチです。

コード

#from typing import Iterable 
from collections import Iterable                            # < py38


def flatten(items):
    """Yield items from any nested iterable; see Reference."""
    for x in items:
        if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
            for sub_x in flatten(x):
                yield sub_x
        else:
            yield x

  • Pythonの3では、yield from flatten(x)交換することができますfor sub_x in flatten(x): yield sub_x
  • Python 3.8では、抽象基本クラスはからモジュールに移動collection.abcましたtyping

デモ

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

参照

  • このソリューションは、Beazley、D。、およびB. Jonesのレシピから変更されています。レシピ4.14、Python Cookbook 3rd Ed。、O'Reilly Media Inc. Sebastopol、CA:2013。
  • 以前のSOの投稿、おそらくオリジナルのデモが見つかりました。

5
あなたの解決策が見つからなかったので、私はほとんど同じように書いただけです...ここで私が探したのは「再帰的に完全な複数のリストを平坦化する」です...(+1)
Martin Thoma

3
@MartinThomaありがとうございます。ちなみに、ネストされたイテラブルをフラット化することが一般的な方法である場合、これをうまく処理するサードパーティのパッケージがいくつかあります。これにより、ホイールを再発明する必要がなくなります。私はmore_itertoolsこの記事で議論された他のものの中で言及しました。乾杯。
pylang 2017年

おそらくtraverse、ツリーのこの方法には良い名前かもしれませんが、ネストされたリストに固執することで、この答えの普遍性を低くします。
Wolf

if hasattr(x, '__iter__')インポート/ チェックの代わりにチェックすることができIterable、文字列も除外されます。
ライアンアレン

ネストされたリストの1つに文字列のリストがある場合、上記のコードは機能しないようです。[1、2、[3、4]、[4]、[]、9、9.5、 'ssssss'、['str'、 'sss'、 'ss']、[3、4、5]]出力: -[1、2、3、4、4、9、9.5、「sssssss」、3、4、5]
sunnyX

51

ネストの深さがわからないデータ構造をフラット化したい場合は、次のように使用できます1iteration_utilities.deepflatten

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

これはジェネレータなので、結果をにキャストするlistか、明示的に反復する必要があります。


1つのレベルのみを平坦化し、各アイテム自体が反復可能である場合は、iteration_utilities.flattenそれ自体を単に薄いラッパーとして使用することもできますitertools.chain.from_iterable

>>> from iteration_utilities import flatten
>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> list(flatten(l))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

いくつかのタイミングを追加するだけです(この回答で提示された関数を含まないNicoSchlömerの回答に基づく):

ここに画像の説明を入力してください

これは、広範囲にわたる値の範囲に対応するための対数-対数プロットです。定性的推論の場合:低いほど良い。

結果は、反復可能オブジェクトに含まsumれる内部反復可能オブジェクトが数個しかない場合は最速になりますが、長い反復可能オブジェクトの場合はのみitertools.chain.from_iterableiteration_utilities.deepflattenまたはネストされた内包表記がitertools.chain.from_iterable最速で妥当なパフォーマンスを持っていることを示しています(ニコシュレーマーがすでに気づいているように)。

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免責事項:私はそのライブラリの作成者です


sum任意のシーケンスで動作しなくなり、それはで始まるとして0作り、functools.reduce(operator.add, sequences)交換を(我々は、彼らが削除喜んではありませんreduce組み込みコマンドから?)。タイプがわかっている場合は、使用する方が速い場合がありますtype.__add__
Yann Vernier、2018年

@YannVernier情報をありがとう。私はこれらのベンチマークをPython 3.6で実行し、それがで動作すると思っていましたsum。あなたはたまたまそれが動作しなくなったPythonのバージョンを知っていますか?
MSeifert、2018年

ちょっと勘違いしてました。0はデフォルトの開始値にすぎないため、start引数を使用して空のリストで開始すると機能しますが、それでも特殊な文字列であり、結合を使用するように指示されます。のfoldl代わりに実装していますfoldl1。同じ問題が2.7で発生します。
Yann Vernier、

39

私は私の声明を取り戻します。合計は勝者ではありません。リストが小さいほど高速ですが。ただし、リストが大きくなると、パフォーマンスは大幅に低下します。

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

合計バージョンはまだ1分以上実行されており、まだ処理を行っていません!

中規模リストの場合:

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

小さなリストとtimeitを使用する:number = 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

23
本当に小さなリスト、たとえば3つのサブリストがあるものの場合-多分-しかし、合計のパフォーマンスはO(N ** 2)であり、リストの内包はO(N)であるので、入力リストを少し増やすだけで逆になります- -実際、LCはNが大きくなるにつれて、限界での合計よりも「無限に速く」なります。私は合計の設計とPythonランタイムでの最初の実装を担当していましたが、合計数(実際には何が得意か)に効果的に制限して、人々に提供する「魅力的な迷惑」をブロックする方法が見つかれば幸いでしたリストを「合計」したい人;-)。
Alex Martelli、

38

と混同されているようoperator.addです。2つのリストを一緒に追加する場合、そのための正しい用語concatは追加ではなくです。operator.concatあなたが使用する必要があるものです。

あなたが機能的だと思っているなら、それはこれと同じくらい簡単です::

>>> from functools import reduce
>>> list2d = ((1, 2, 3), (4, 5, 6), (7,), (8, 9))
>>> reduce(operator.concat, list2d)
(1, 2, 3, 4, 5, 6, 7, 8, 9)

reduceはシーケンスタイプを尊重していることがわかります。そのため、タプルを指定すると、タプルが返されます。リストで試してみましょう::

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

ああ、あなたはリストを取り戻します。

パフォーマンスについて::

>>> 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かなり速いです!しかし、で削減するのは比較にならないconcat

>>> list2d = ((1, 2, 3),(4, 5, 6), (7,), (8, 9))
>>> %timeit reduce(operator.concat, list2d)
1000000 loops, best of 3: 492 ns per loop


2
そのような小さな入力を使用することは、それほど公平な比較ではありません。長さが1000の1000シーケンスの場合、は0.037秒list(chain.from_iterable(...))、は2.5秒ですreduce(concat, ...)。問題は、線形reduce(concat, ...)であるのに対して、実行時間が2次であることchainです。
kaya3

33

なぜエクステンドを使うのですか?

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

これは正常に動作するはずです。


7
python3の場合from functools import reduce
andorov

すみません、それは本当に遅いです。残りの回答を見てください
Mr_and_Mrs_D

これは、Python 2と3で動作する非常に簡単に理解できる短い解決策です。多くのPython関係者が、大量のデータを処理するために速度を重視するデータ処理を行っていることに気づきますが、シェルスクリプトを書いていて、いくつかのサブリストに数十の要素しかないので、これは完璧です。
Asfand Qazi 2018

27

more_itertoolsパッケージのインストールを検討してください。

> pip install more_itertools

flattenSourceitertoolsレシピから)の実装とともに出荷されます

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]

バージョン2.4以降では、more_itertools.collapsesource、abarnetによって提供された)を使用して、より複雑でネストされた反復可能オブジェクトをフラット化できます。

lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(more_itertools.collapse(lst)) 
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

lst = [[1, 2, 3], [[4, 5, 6]], [[[7]]], 8, 9]              # complex nesting
list(more_itertools.collapse(lst))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

確かに。これは受け入れられる答えになるはずです
Brunetton

プロジェクトにパッケージを追加する余裕がある場合-この答えが最善です
viddik13

22

関数が機能しなかった理由は、extendが配列をその場で拡張し、それを返さないためです。次のようなものを使用して、ラムダからxを返すことができます。

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

注:リストの場合、拡張は+よりも効率的です。


7
extendより良いとして使用されているnewlist = []extend = newlist.extendfor sublist in l: extend(l)それは(かなり大きい)を避けるようオーバーヘッドのlambda、属性の検索x、およびor
agf 2011

Python 3の追加from functools import reduce
Markus Dutschke

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

def flatten(l, a=None): if a is None: a = [][...]
Poik

16

再帰バージョン

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
いいですね、インポートは必要ありません。それが何をしているかは明らかです...リストをフラット化し、ピリオド:)
ゴランB.

1
単に素晴らしいです!
Sachin Sharma

15

matplotlib.cbook.flatten() ネストされたリストは、例よりも深くネストされていても機能します。

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

結果:

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

これは、アンダースコアより18倍高速です。_。flatten:

Average time over 1000 trials of matplotlib.cbook.flatten: 2.55e-05 sec
Average time over 1000 trials of underscore._.flatten: 4.63e-04 sec
(time for underscore._)/(time for matplotlib.cbook) = 18.1233394636

14

可変長のテキストベースのリストを扱うとき、受け入れられた答えは私にはうまくいきませんでした。ここに私のために働いた別のアプローチがあります。

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

うまくいかなかった受け入れられた答え:

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

新ソリューション提案でした私のために仕事を:

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

13

上記のAnilの関数の悪い特徴は、ユーザーが2番目の引数を常に手動で空のリストに指定する必要があること[]です。代わりに、これがデフォルトになります。Pythonオブジェクトの動作方法により、これらは引数ではなく関数内で設定する必要があります。

これが機能する関数です:

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

テスト:

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]

13

以下は私にとって最も簡単に思えます:

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

ディメンションが異なるリストでは機能しません。-1
nurub

10

NumPyのフラットを使用することもできます。

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

編集11/02/2016:サブリストのディメンションが同じ場合にのみ機能します。


それは最適なソリューションでしょうか?
RetroCode、2016

6

あなたはnumpyを使うことができます:
flat_list = list(np.concatenate(list_of_list))


これは、数値、文字列、混合リストでも機能します
Nitin

2
同様に、不均等にネストされたデータのために失敗する[1, 2, [3], [[4]], [5, [6]]]
EL_DON

5

見栄えを良くするために少し速度をあきらめたい場合は、numpy.concatenate().tolist()またはを使用できますnumpy.concatenate().ravel().tolist()

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

詳しくは、ドキュメントnumpy.concatenateおよびnumpy.ravelをご覧ください。


1
以下のような不均一ネストされたリストでは動作しません[1, 2, [3], [[4]], [5, [6]]]
EL_DON

5

私が見つけた最速の解決策(とにかく大きなリストの場合):

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

できた!もちろん、list(l)を実行することでリストに戻すことができます


1
これは間違っています。flattenはnd配列の次元を1に減らしますが、内部のリストを1つとして連結しません。
安藤ジュライ2017年

5

underscore.pyパッケージファンのシンプルなコード

from underscore import _
_.flatten([[1, 2, 3], [4, 5, 6], [7], [8, 9]])
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

すべてのフラット化問題を解決します(リストアイテムや複雑なネストはありません)

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]

あなたはunderscore.pypipでインストールできます

pip install underscore.py

同様に、pydashを使用できます。このバージョンは、リスト内包表記やその他の答えよりもはるかに読みやすいと思います。
gliemezis 2017

2
これはとても遅いです。
NicoSchlömer2017

2
_という名前のモジュールがあるのはなぜですか?それは悪い名前のようです。stackoverflow.com/a/5893946/6605826を
EL_DON 2018

2
@EL_DON:underscore.py readmeページから「Underscore.pyは、優れたJavaScriptライブラリunderscore.jsのpython移植版です」。それがこの名前の理由だと思います。そしてはい、それはpythonの良い名前ではありません
Vu Anh

5
def flatten(alist):
    if alist == []:
        return []
    elif type(alist) is not list:
        return [alist]
    else:
        return flatten(alist[0]) + flatten(alist[1:])

:問題の例ネストされたリストのためのpython2.7のために失敗する[[1, 2, 3], [4, 5, 6], [7], [8, 9]]
EL_DON

@EL_DONはPython 2.7.5でテストされています。それはうまくいく
englealuze

5

:はを使用してyield_fromいるため、以下はPython 3.3以降に適用されます。 six安定していますが、サードパーティのパッケージでもあります。または、を使用することもできますsys.version


の場合、obj = [[1, 2,], [3, 4], [5, 6]]リスト内包表記やを含め、ここでのすべての解決策は適切itertools.chain.from_iterableです。

ただし、この少し複雑なケースを検討してください。

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

ここにはいくつかの問題があります:

  • 1つの要素6は単なるスカラーです。反復可能ではないため、上記のルートはここで失敗します。
  • 一つの要素は、'abc'である(すべての技術的に反復可能なstrのです)。ただし、行間を少し読むと、そのように扱いたくない-単一の要素として扱いたい場合。
  • 最後の要素は、[8, [9, 10]]それ自体がネストされた反復可能です。基本的なリストの理解とchain.from_iterable「1レベル下」のみを抽出します。

これは次のように修正できます。

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

ここでは、サブエレメント(1)がIterableABC from itertoolsで反復可能であることを確認しますが、(2)エレメントが「文字列のような」ものではないことを確認したいとします。


1
それでもPython 2の互換性に関心がある場合はyield fromforループに変更してください。たとえば、for x in flatten(i): yield x
pylang

5
flat_list = []
for i in list_of_list:
    flat_list+=i

このコードは、リストを完全に拡張するだけなので、正常に機能します。よく似ていますが、forループは1つしかありません。したがって、2つのforループを追加するよりも複雑さが少なくなります。


5
from nltk import flatten

l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
flatten(l)

ここで他のほとんどのソリューションに対するこのソリューションの利点は、次のようなリストがある場合です。

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

他のほとんどのソリューションはエラーをスローしますが、このソリューションはそれらを処理します。


質問には「リストのリスト」と記載されていますが、サンプルリストにはリスト以外のアイテムが含まれています。他のほとんどの解決策は、元の質問に固執しています。あなたのソリューションはより広い問題を解決しますが、最初にインストールする必要がある非ベースPythonパッケージ(nltk)も必要です。
シモノボ

4

これは最も効率的な方法ではないかもしれませんが、1ライナー(実際には2ライナー)を使用することを考えました。どちらのバージョンも、任意の階層のネストされたリストで機能し、言語機能(Python3.5)と再帰を利用します。

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)

出力は

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

これは、深さ優先で機能します。再帰は、リスト以外の要素が見つかるまで続き、ローカル変数flistを拡張して、親にロールバックします。flist返されるときはいつでもflist、リスト内包の親のものに拡張されます。したがって、ルートではフラットリストが返されます。

上記のものはいくつかのローカルリストを作成し、それらを返します。これらは親のリストを拡張するために使用されます。これを回避する方法は、flist以下のようにgloablを作成することだと思います。

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)

出力は再びです

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

現時点では効率についてはわかりませんが。


なぜappend(l)の代わりにextend([l])を使うのですか?
Maciek

3

整数のヘテロリストおよび同種リストで機能する別の珍しいアプローチ:

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

これは、complicated3000が以前に投稿したものよりも複雑で少し遅い方法です。私は昨日彼の提案を再発明したので、このアプローチは最近非常に人気があるようです;)
Darkonaut

かなり: wierd_list = [[1, 2, 3], [4, 5, 6], [7], [8, 9], 10]>>nice_list=[1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 0]
tharndt

1つのライナーとしての私のコードは次のようになります flat_list = [int(e.replace('[','').replace(']','')) for e in str(deep_list).split(',')]
tharndt

1
あなたは確かに正しい+1であり、ᴡʜᴀᴄᴋᴀᴍᴀᴅᴏᴏᴅʟᴇ3000の提案は複数桁の数字では機能しません。これも以前からテストしていませんが、明白なはずです。コードを簡略化して記述できます[int(e.strip('[ ]')) for e in str(deep_list).split(',')]。しかし、実際のユースケースについては、Deleetの提案を守ることをお勧めします。ハックタイプの変換は含まれていません。混合タイプのリストも当然処理するため、より高速で多用途です。
Darkonaut

2
残念だけど違う。しかし、私はこのコードを最近ここで見ました: Pythonプラクティスブック 6.1.2
tharndt
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.