web-dev-qa-db-ja.com

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

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'
2575
Emma

リストのリストがlであるとすると、

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

つまり、

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での暗黙の使用を含む)は、必然的に、L個のサブリストがある場合はO(L**2)です。前の中間結果のすべての項目をコピーする必要があります(最後にいくつかの新しい項目も追加します)。そのため、単純にして一般性を失うことなく、それぞれI項目のL個のサブリストがあるとします。コピーの総数は、除外された1からLまでのxについて、xにxの合計を掛けたもの、すなわちI * (L**2)/2である。

リスト内包表記は1つのリストを1回だけ生成し、各アイテムを元の場所から結果リストに1回だけコピーします。

3548
Alex Martelli

itertools.chain() を使用できます。

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

あるいは、Python> = 2.6では、 itertools.chain.from_iterable() を使います。

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

このアプローチは[item for sublist in l for item in sublist]よりも間違いなく読みやすく、より速いようです:

[me@home]$ 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
[me@home]$ 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
[me@home]$ 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
[me@home]$ 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
[me@home]$ python --version
Python 2.7.3
1222
Shawn Chin

作者からのメモ :これは非効率的です。 モノイド はすごいですから。本番Pythonコードには適していません。

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

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

ネストしたリストを集計しているので、実際にはsum([[1,3],[2,4]],[])の結果として[1,3]+[2,4]が得られます。これは[1,3,2,4]と同じです。

リストのリストに対してのみ機能することに注意してください。リストのリストのリストについては、別の解決策が必要です。

709
Triptych

私は perfplot (私のペットプロジェクト、基本的にtimeitのラッパー)で最も推奨される解決策をテストし、そして

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

最速のソリューションです。 (operator.iaddは同じくらい速いです。)

enter image description here


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

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]

あなたの例の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]
121
Greg Hewgill

これは、 数字 文字列 ネスト リスト、および mixed コンテナに適用される一般的な方法です。

コード

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

注:Python 3では、yield from flatten(x)for sub_x in flatten(x): yield sub_xを置き換えることができます

デモ

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. and B. Jones。Recipe 4.14、Python Cookbook 3版、O'Reilly Media Inc. Sebastopol、CA:2013のレシピから修正されています。
  • 以前の SO post 、おそらく最初のデモを見つけました。
72
pylang

ネストの深さがわからないデータ構造をフラット化する場合は、 iteration_utilities.deepflatten を使用できます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]

それはジェネレータなので、結果を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の回答に基づく)。

enter image description here

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

結果は、イテラブルが少数の内部イテラブルのみを含む場合、sumが最速になることを示していますが、長いイテラブルでは、itertools.chain.from_iterableiteration_utilities.deepflatten、またはネストされた内包表記のみが、itertools.chain.from_iterableが最速で合理的なパフォーマンスを発揮します(すでにNicoシュレーマー)。

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

42
MSeifert

私は声明を取り戻す。合計は勝者ではありません。リストが小さいときは速いですが。しかし、リストが大きいとパフォーマンスが著しく低下します。  

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

Sumバージョンはまだ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
34
Nadia Alramli

なぜあなたはextendを使いますか?

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

これはうまくいくはずです。

28
Andrea Ambu

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

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

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

あなたはreduceがシーケンスタイプを尊重しているのを見るので、あなたがTupleを供給するとき、あなたはTupleを取り戻します。リストで試してみましょう::

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

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

> pip install more_itertools

flattenitertoolsレシピsource )の実装が付属しています。

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

あなたの関数が機能しなかった理由:extendは配列をその場で拡張して返しません。あなたはまだいくつかのトリックを使用して、ラムダからxを返すことができます:

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

注:リストの+よりもextendの方が効率的です。

16
Igor Krivokon

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

...セットアップツール

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

上記の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]
10
Deleet

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

>>> 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()はネストしたリストに対して機能します。

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倍高速です。

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

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

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

notが効いたと思われる回答:

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

didが私のために働くという新しい提案された解決策:

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

NumPyの flat を使うこともできます。

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

編集11/02/2016:サブリストの寸法が同じ場合にのみ機能する.

7
mdh

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

5
A. Attia

underscore.py package fanの簡単なコード

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.py をpipでインストールできます

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

整数のヘテロリストおよびホモジニアスリストに有効なもう1つの珍しいアプローチ

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

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

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

完了しました。もちろんlist(l)を実行してリストに戻すこともできます。

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

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

3
Deepak Yadav

あなたがよりきれいな外観のためにわずかな量のスピードをあきらめても構わないと思っているなら、あなたは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.concatenatenumpy.ravel をご覧ください。

3
mkultra

reduceからのfunctoolsとリストに対するadd演算子を使った簡単な再帰的方法:

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

関数flattenは、パラメータとしてlstを受け取ります。整数に達するまでlstのすべての要素をループします(他のデータ型ではintfloatstrなどに変更することもできます)。これは最外部の再帰の戻り値に追加されます。

forループやモナドのようなメソッドとは異なり、再帰は リストの深さに制限されない一般的な解決策 です。たとえば、深さ5のリストはlと同じ方法で平坦化できます。

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

私は最近、次のようなサブリストに文字列と数値データが混在している状況に遭遇しました。

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

flat_list = [item for sublist in test for item in sublist]のようなメソッドが機能していないところ。それで、私はサブリストの1+レベルのために以下の解決策を思いつきました

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

そしてその結果

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

これは最も効率的な方法ではないかもしれませんが、私は1ライナー(実際には2ライナー)を置くことを考えました。どちらのバージョンも任意の階層のネストしたリストで動作し、言語機能(Python 3.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を作成します。

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]

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

2
phoxis

:Python 3.3以降では yield_from を使用しているため、以下が適用されます。 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は単なるスカラです。これは反復可能ではないので、上記の経路はここで失敗します。
  • 1つの要素、'abc'isは技術的に反復可能です(すべての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]

ここでは、sub-element(1)がIterableからのABCである itertools で反復可能であることを確認しますが、(2)要素がnot "であることを確認します。 「

2
Brad Solomon

実際のスタックデータ構造を使用することで、スタックへの再帰呼び出しを簡単に回避できます。

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

再帰バージョン

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

リングに私の帽子を投げています...

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

これは toolz.concat またはcytoolz.concat(cythonized版、場合によってはもっと速いかもしれません)を使って行うことができます。

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

私のコンピューターでは、Python 3.6では、これは[item for sublist in l for item in sublist]とほぼ同じくらいの時間で行われるようです(インポート時間はカウントしません)。

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)

toolzバージョンは確かに遅くなります。

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

質問は、「ワンライナー」のクールな答えを求めました。次に、プレーン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

私の解決策(直感的で短い):

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

あなたはDaskを使ってリストを平らにしたり/マージしたりすることができ、さらにメモリ節約の利点があります。 Daskは、compute()でのみアクティブになる遅延メモリを使用します。だからあなたはあなたのリストでDask Bag APIを使い、それから最後にそれをcompute()することができます。ドキュメント: 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

より遅い(実行時間の)ルートを取る場合、文字列をチェックするよりも先に進む必要があります。タプルのネストされたリスト、リストのタプル、またはユーザー定義の反復可能な型のシーケンスがある場合があります。

入力シーケンスから型を取得し、それに対してチェックします。

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

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

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

0
Kevin Postal

あなたはチェーンクラスを使用することができます

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

出力は次のようになります。[A B C D E F]

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

0
Balamurugan

これは任意にネストされたリストで動作します。他の種類のイテラブルを扱うように簡単に拡張することができます。

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

サンプル実行

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

これは、任意のネストされたリストで機能する再帰を使用した関数です。

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

これを行う別の楽しい方法:

from functools import reduce
from operator import add

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

Pythonの基本概念を使っても同じことができます。 

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