リストの平坦化、つまり入れ子になったリストを1レベルのリストに変換する処理は、Pythonでよくあるタスクです。この記事では、これを達成するための様々な手法を、平坦化の深さ(浅い平坦化と深い平坦化)によって分類して解説します。
目次
浅い平坦化
浅い平坦化は、入れ子のレベルを1つだけ削除します。内側のリストがさらに入れ子構造を含まないリストのリストを持っている場合に最適です。効率的な方法は2つあります。
リスト内包表記: 簡潔で読みやすい解決策を提供します。
nested_list = [[1, 2, 3], [4, 5], [6]]
flat_list = [item for sublist in nested_list for item in sublist]
print(flat_list) # 出力: [1, 2, 3, 4, 5, 6]
itertools.chain.from_iterable
: より大きなリストの場合、最適化された反復処理により、このアプローチの方がパフォーマンスが向上します。
from itertools import chain
nested_list = [[1, 2, 3], [4, 5], [6]]
flat_list = list(chain.from_iterable(nested_list))
print(flat_list) # 出力: [1, 2, 3, 4, 5, 6]
制限事項: 浅い平坦化は、入れ子になったリストの中にさらに入れ子になったリストがあるリストを完全に平坦化できません。例えば:
nested_list = [[1, 2, [3, 4]], [5, 6]]
flat_list = [item for sublist in nested_list for item in sublist]
print(flat_list) # 出力: [1, 2, [3, 4], 5, 6]
内側のリスト[3, 4]
は入れ子のままです。
深い平坦化
深い平坦化は、任意の深さの入れ子になったリストを再帰的に処理します。主なアプローチは2つあります。
再帰関数: このエレガントな解決策は、再帰を使用して入れ子構造を走査します。
def flatten(nested_list):
flat_list = []
for item in nested_list:
if isinstance(item, list):
flat_list.extend(flatten(item))
else:
flat_list.append(item)
return flat_list
nested_list = [[1, 2, [3, 4]], [5, 6, [7, [8, 9]]]]
flat_list = flatten(nested_list)
print(flat_list) # 出力: [1, 2, 3, 4, 5, 6, 7, 8, 9]
反復的なアプローチ(スタックを使用): 再帰は、非常に深い入れ子構造ではスタックオーバーフローエラーにつながる可能性があります。スタックを使用した反復的なアプローチは堅牢性を提供します。
def flatten_iterative(nested_list):
flat_list = []
stack = [nested_list]
while stack:
current = stack.pop()
if isinstance(current, list):
stack.extend(current)
else:
flat_list.append(current)
return flat_list
nested_list = [[1, 2, [3, 4]], [5, 6, [7, [8, 9]]]]
flat_list = flatten_iterative(nested_list)
print(flat_list) # 出力: [1, 2, 3, 4, 5, 6, 7, 8, 9]
結論
浅い平坦化と深い平坦化のどちらを選択するかは、入れ子になったリストの構造に完全に依存します。浅い平坦化は、単一レベルの入れ子構造の場合に十分であり、簡潔で効率的な解決策を提供します。しかし、任意に入れ子になったリストの場合、堅牢性のために反復的なスタックベースのアプローチを使用する深い平坦化が必要になります。