4528

Pythonでリストのリストから単純なリストを作成するショートカットはありますか?

ループで実行できますforが、クールな「ワンライナー」はありますか?

私はそれを試しましたfunctools.reduce()

from functools import 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'
4

26 に答える 26

6403

リストのリストが与えられるとt

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

つまり:

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

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

対応する関数は次のとおりです。

def flatten(t):
    return [item for sublist in t for item in sublist]

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

$ python -mtimeit -s't=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in t for item in sublist]'
10000 loops, best of 3: 143 usec per loop
$ python -mtimeit -s't=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(t, [])'
1000 loops, best of 3: 969 usec per loop
$ python -mtimeit -s't=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,t)'
1000 loops, best of 3: 1.1 msec per loop

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

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

于 2009-06-04T20:37:01.207 に答える
2005

使用できますitertools.chain()

import itertools

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

または、 operatoritertools.chain.from_iterable()を使用してリストをアンパックする必要のない whichを使用できます。*

merged = list(itertools.chain.from_iterable(list2d))
于 2009-06-04T21:06:17.763 に答える
1170

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

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

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

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

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

于 2009-06-04T20:35:53.563 に答える
760

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

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

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

より単純で許容可能な変形は次のとおりです。

out = []
for sublist in a:
    out.extend(sublist)

サブリストの数が多い場合、これは上記の提案よりもパフォーマンスが少し悪くなります。

ここに画像の説明を入力

ここに画像の説明を入力


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

import functools
import itertools
import operator

import numpy as np
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(np.array(a).flat)


def numpy_concatenate(a):
    return list(np.concatenate(a))


def extend(a):
    out = []
    for sublist in a:
        out.extend(sublist)
    return out


b = perfplot.bench(
    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,
        extend,
    ],
    n_range=[2 ** k for k in range(16)],
    xlabel="num lists (of length 10)",
    # xlabel="len lists (10 lists total)"
)
b.save("out.png")
b.show()
于 2017-07-26T09:38:16.403 に答える
262
>>> from functools import reduce
>>> 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、有用な値を返す代わりに変更します(functools.reduce()期待されます)。

reduceバージョンを実行するより高速な方法は次のとおりです。

>>> from functools import 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]
于 2009-06-04T20:35:30.430 に答える
157

これは、数値文字列ネストされたリスト、および混合コンテナーに適用される一般的なアプローチです。これにより、単純なコンテナーと複雑なコンテナーの両方をフラット化できます ( Demoも参照)。

コード

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

デモ

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

complicated = [[1, [2]], (3, 4, {5, 6}, 7), 8, "9"]              # numbers, strs, nested & mixed
list(flatten(complicated))
# [1, 2, 3, 4, 5, 6, 7, 8, '9']

参照

  • このソリューションは、 Beazley、D.、および B. Jonesのレシピから変更されています。レシピ 4.14、Python クックブック第 3 版、O'Reilly Media Inc.、カリフォルニア州セバストポール: 2013。
  • おそらく元のデモンストレーションである、以前のSO投稿を見つけました。
于 2016-11-29T04:14:45.637 に答える
87

ネストの深さが分からないデータ構造を平坦化したい場合は、1を使用できます。iteration_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.flattenwhich それ自体が単なる薄いラッパーである を使用することもでき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]

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

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

これは、膨大な範囲の値に対応する対数対数プロットです。定性的な理由: 低いほど良い。

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

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

于 2016-11-26T00:20:37.347 に答える
39

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

> pip install more_itertools

flatten( sourceitertools レシピから)の実装が同梱されています。

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]

注: docsに記載されているようにflatten、リストのリストが必要です。より不規則な入力の平坦化については、以下を参照してください。


バージョン 2.4 の時点で、より複雑でネストされた iterable をmore_itertools.collapse( source、 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]
于 2016-12-02T18:35:17.803 に答える
32

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

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

注: リストでは、extend は + よりも効率的です。

于 2009-06-04T20:47:13.743 に答える
16

NumPy のflatを使用することもできます:

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

サブリストの次元が同じ場合にのみ機能します。

于 2016-07-17T12:57:48.257 に答える
16

1つのリストレベルであるリストによると、ライブラリを使用せずに[[1, 2, 3], [4, 5, 6], [7], [8, 9]]簡単に使用できますsum(list,[])

sum([[1, 2, 3], [4, 5, 6], [7], [8, 9]],[])
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
于 2021-12-09T09:15:47.340 に答える
8

見栄えを良くするために速度を少し犠牲にしても構わない場合は、numpy.concatenate().tolist()orを使用でき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を参照してください。

于 2016-10-27T03:24:08.400 に答える
5
def flatten(alist):
    if alist == []:
        return []
    elif type(alist) is not list:
        return [alist]
    else:
        return flatten(alist[0]) + flatten(alist[1:])
于 2017-08-08T14:59:07.703 に答える
1

任意の深さのリストのリストを平坦化する非再帰関数:

def flatten_list(list1):
    out = []
    inside = list1
    while inside:
        x = inside.pop(0)
        if isinstance(x, list):
            inside[0:0] = x
        else:
            out.append(x)
    return out

l = [[[1,2],3,[4,[[5,6],7],[8]]],[9,10,11]]
flatten_list(l)
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
于 2021-12-09T06:10:17.333 に答える