1. ホーム
  2. python

[解決済み] リストのリストからフラットなリストを作るには?

2022-03-15 15:55:06

質問

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'

解決方法は?

リストのリストがある場合 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) 中間結果リストが長くなると、各ステップで新しい中間結果リストオブジェクトが 割り当てられ、前の中間結果のすべての項目がコピーされなければなりません (さらに最後にいくつかの新しい項目が追加されます)。そこで、簡単のために、また実際に一般性を失うことなく、それぞれk個の項目からなるT個のサブリストがあるとします。最初のk個の項目はT-1回、2番目のk個の項目はT-2回、・・・とコピーして行き、コピー回数は1からTまでのxの合計のk倍になります、即ち。 k * (T**2)/2 .

リスト内包はただ一度だけリストを生成し、各項目を(元の場所から結果のリストへ)正確に一度だけコピーします。