リストは Python で最も柔軟なデータ構造です。
リストのリストを平坦化するには、リストのリストに格納されている各項目の入れ子を解除して、2次元リストを1次元リストに変換します。
すなわち、 [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
を [1, 2, 3, 4, 5, 6, 7, 8, 9]
に変換するのです。
平坦化の処理は、ネストされたリストの規則性と深さに応じて、ネストされたforループ、リスト内包、再帰、組み込み関数、またはPythonのライブラリのインポートによって実行することができる。
ネストされたリストの種類
Pythonは弱い型付けなので、リストの中の正規のリストと不規則なリストに遭遇することがあります。
通常のリスト
このリストのすべての要素はサブリストであり、それによって要素の型の統一が守られている。
例: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
は [1, 2, 3], [4, 5, 6], [7, 8, 9]
が list
型であるため、リストの正規リストとなる。
イレギュラーリストのリスト
このリストのすべての要素はサブリストか、リスト以外の項目(たとえば整数や文字列)である。
したがって、要素の型という点では不規則性がある。
例: [[1, 2, 3], [4, 5], 6]
ここで、 [1, 2, 3]
と [4, 5]
は list
型であり、 6
は int
型である。
ネストされたforループを使用してリストのリストを平坦化する。
これは、リストのリストからすべての要素を選んで1次元のリストに入れることで、平らなリストを得るという強引な方法です。
コードは以下のように直感的で、リストの規則的なリストと不規則なリストの両方に対して動作します。
def flatten_list(_2d_list):
flat_list = []
# Iterate through the outer list
for element in _2d_list:
if type(element) is list:
# If the element is of type list, iterate through the sublist
for item in element:
flat_list.append(item)
else:
flat_list.append(element)
return flat_list
nested_list = [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
print('Original List', nested_list)
print('Transformed Flat List', flatten_list(nested_list))
この結果、次のようになる。
Original List [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
Transformed Flat List [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
リスト理解を使ってリストのリストを平坦化する。
この方法は、既存の2次元リストに基づいて平坦なリストを作成するためのエレガントなソリューションですが、直感的なものではありません。
regular_list = [[1, 2, 3, 4], [5, 6, 7], [8, 9]]
flat_list = [item for sublist in regular_list for item in sublist]
print('Original list', regular_list)
print('Transformed list', flat_list)
これは次のように出力される。
Original list [[1, 2, 3, 4], [5, 6, 7], [8, 9]]
Transformed list [1, 2, 3, 4, 5, 6, 7, 8, 9]
リストのリストを再帰的に平坦化する
2次元リストも再帰的に平坦化することができる。
以下の実装は、通常のリストと不規則なリストの両方に対して動作する。
def flatten(list_of_lists):
if len(list_of_lists) == 0:
return list_of_lists
if isinstance(list_of_lists[0], list):
return flatten(list_of_lists[0]) + flatten(list_of_lists[1:])
return list_of_lists[:1] + flatten(list_of_lists[1:])
print(flatten([[1, 2, 3, 4], [5, 6, 7], [8, 9], 10]))
これは次のようになる。
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
ライブラリの利用について
この作業には、Pyhonのライブラリの助けを借りることもできます。
functools (reduce() と iconcat()) を使ってリストのリストを平坦化する
iconcat()` 関数は、連結の基本的な操作を行うもので、リストの項目の左から右に累積的に適用して、1つのリストに縮小します。
import functools
import operator
regular_list = []
# Transform irregular 2D list into a regular one.
def transform(nested_list):
for ele in nested_list:
if type(ele) is list:
regular_list.append(ele)
else:
regular_list.append([ele])
return regular_list
irregular_list = [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10], 11]
regular_2D_list = transform(irregular_list)
print('Original list', irregular_list)
print('Transformed list', functools.reduce(operator.iconcat, regular_2D_list, []))
となり、望ましい結果が得られます。
Original list [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10], 11]
Transformed list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
itertools を使ってリストのリストを平らにする (chain())
この方法は、引数として渡されたイテラブルを順次処理することで、連続したシーケンスを1つのシーケンスとして扱うため、2次元リストを1つのフラットリストに変換するのに適しています。
import itertools
regular_list = [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
flat_list = list(itertools.chain(*regular_list))
print('Original list', regular_list)
print('Transformed list', flat_list)
この場合も、出力として平坦化されたリストが得られます。
Original list [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
Transformed list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numpyを使ったリストの平坦化 (concatenate() と flat())
Numpyには、通常の2次元配列を行単位、列単位で連結するような一般的な操作があります。
また、flat
属性を使って、配列に対する1次元イテレータを取得することで、目的を達成します。
しかし、この方法は比較的時間がかかります。
import numpy
regular_list = [[1, 2, 3, 4], [5, 6, 7], [8, 9]]
flat_list = list(numpy.concatenate(regular_list).flat)
print('Original list', regular_list)
print('Transformed list', flat_list)
しかし、この方法は比較的時間がかかります。
Original list [[1, 2, 3, 4], [5, 6, 7], [8, 9]]
Transformed list [1, 2, 3, 4, 5, 6, 7, 8, 9]
ビルトイン関数の使用
Pythonが提供する組み込み関数を使って、平坦化の作業を行うこともできます。
sum を使ってリストのリストを平らにする
内部リストの合計も解決策のひとつです。
この関数には 2 つのパラメータがあります。
この関数は、リストのリストである iterable
と、内部のサブリストの項目を追加するための初期フラットリストとなる start
(この例では空のリスト) の 2 つのパラメータを持ちます。
この方法は、何もインポートする必要がないので便利ですが、サブリストの数が多い場合には、 itertools()
や chain()
関数よりも遅くなります。
regular_list = [[1, 2, 3, 4], [5, 6, 7], [8, 9]]
flat_list = sum(regular_list, [])
print('Original list', regular_list)
print('Transformed list', flat_list)
出力で
Original list [[1, 2, 3, 4], [5, 6, 7], [8, 9]]
Transformed list [1, 2, 3, 4, 5, 6, 7, 8, 9]
Lambdaを使ってリストのリストを平らにする
lambdaキーワードを使って無名関数を定義することができます。
この無名関数の引数に正規/非正規リストを渡し、その式を評価することで、平坦な1次元リストを得ることができます。
irregular_list = [[1, 2, 3], [3, 6, 7], [7, 5, 4],7]
# Using lambda arguments: expression
flatten_list = lambda irregular_list:[element for item in irregular_list for element in flatten_list(item)] if type(irregular_list) is list else [irregular_list]
print("Original list ", irregular_list)
print("Transformed List ", flatten_list(irregular_list))
再び望ましい結果を得ることができるだろう。
Original list [[1, 2, 3], [3, 6, 7], [7, 5, 4], 7]
Transformed List [1, 2, 3, 3, 6, 7, 7, 5, 4, 7]
結論
この記事では、Pythonでリストのリストを平坦化するタスクを完了する方法を広範囲に提供しました。