Pythonでプログラミングを行っていると、二次元リストや多重にネストされたリストを一次元の単純なリストに変換したい場面が多々あります。
この操作は一般的に「フラット化」や「ネスト解除」と呼ばれ、データクレンジングやAPIレスポンスの加工において不可欠な技術です。
Pythonには、シンプルに記述できる内包表記から、大規模データに強い標準ライブラリまで、用途に応じた複数の手法が存在します。
この記事では、2026年現在の開発現場で推奨される、効率的で可読性の高いリストのフラット化手法を整理して紹介します。
リスト内包表記による最も標準的なフラット化
Pythonでリストをフラット化する際、最もポピュラーでPythonic(Pythonらしい)とされる手法がリスト内包表記です。
リスト内包表記を使用すると、簡潔なコードで高速に処理を行うことができます。
まずは、もっとも基本的な二次元リストを平坦にする例を見てみましょう。
# 二次元リストの定義
nested_list = [[1, 2, 3], [4, 5], [6, 7, 8, 9]]
# リスト内包表記によるフラット化
flattened = [item for sublist in nested_list for item in sublist]
print(flattened)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
この構文は、外側のループ for sublist in nested_list を先に記述し、その後に内側の要素を取り出す for item in sublist を記述する点に注意が必要です。
この順序は通常の for 文をネストさせた場合の順序と同じであるため、慣れると非常に直感的です。
リスト内包表記は、新しいリストをメモリ上に一気に構築するため、中規模までのデータ処理において非常に高いパフォーマンスを発揮します。
itertools.chain.from_iterable を使ったメモリ効率の良い方法
扱うデータ量が非常に多い場合や、メモリ消費を抑えたい場合には、標準ライブラリの itertools モジュールが最適です。
特に itertools.chain.from_iterable() は、リストをフラット化するための専用の関数として提供されています。
import itertools
# 大規模なネストされたリスト
nested_list = [[i, i + 1] for i in range(0, 1000, 2)]
# イテレータとしてフラット化
flatten_iterator = itertools.chain.from_iterable(nested_list)
# 必要な時にリストに変換
flattened = list(flatten_iterator)
print(flattened[:10])
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
itertools.chain.from_iterable() は、要素を一つずつ生成するイテレータを返します。
そのため、すべての要素を一度にメモリに展開する必要がないという大きな利点があります。
大規模なデータセットを扱うバッチ処理や、ストリーミングデータの加工にはこの手法がベストプラクティスとなります。
深いネストや不規則な構造をフラット化する再帰的アプローチ
これまでに紹介した手法は、ネストの深さが一定(二次元)であることを前提としていました。
しかし、実際の開発では [1, [2, [3, 4], 5], 6] のように、ネストの深さが不規則なデータに遭遇することがあります。
このような場合には、再帰関数を定義して深層まで探索する方法が有効です。
def deep_flatten(lst):
for item in lst:
# 要素がリストまたはタプルであれば再帰的に処理
if isinstance(item, (list, tuple)):
yield from deep_flatten(item)
else:
yield item
# 不規則にネストされたリスト
complex_list = [1, [2, [3, 4], 5], 6, [7, 8]]
# ジェネレータからリストを作成
result = list(deep_flatten(complex_list))
print(result)
[1, 2, 3, 4, 5, 6, 7, 8]
ここでは yield from を使用することで、再帰呼び出しの結果を簡潔に呼び出し元へ戻しています。
ただし、Pythonには再帰呼び出しの回数に制限があるため、極端に深いネスト構造(数千階層など)に対しては注意が必要です。
また、文字列もイテラブルなオブジェクトであるため、要素が文字列の場合に無限ループに陥らないよう、isinstance() による適切な判定が重要になります。
NumPy や Pandas を利用した高度なフラット化
データサイエンスや機械学習の分野で Python を使用している場合、NumPy や Pandas のライブラリを活用するのが最も効率的です。
これらのライブラリは内部が C 言語で最適化されているため、数値計算を伴うフラット化において圧倒的な速度を誇ります。
import numpy as np
# 二次元配列の定義
nested_array = np.array([[1, 2], [3, 4], [5, 6]])
# flattenメソッドを使用
flattened = nested_array.flatten()
print(flattened)
[1 2 3 4 5 6]
NumPy には flatten() の他に ravel() というメソッドも存在します。
flatten() は常にデータのコピーを作成しますが、ravel() は可能な限り元のデータのビューを返します。
メモリ効率を最優先する場合は ravel() を選択するのが定石です。
パフォーマンス比較と手法の選び方
手法が多すぎると、どれを選択すべきか迷うことがあります。
各手法の特性を理解するために、以下の比較表を参考にしてください。
| 手法 | 可読性 | 処理速度 | 柔軟性 | 主な用途 |
|---|---|---|---|---|
| リスト内包表記 | 非常に高い | 高い | 中 | 一般的な二次元リストの処理 |
| itertools.chain | 高い | 最高 | 中 | 大規模データのメモリ節約 |
| 再帰関数 | 中 | 低い | 最高 | 不規則な深いネストの処理 |
| NumPy/Pandas | 高い | 最高(数値) | 低 | 数値計算・行列処理 |
最も避けるべき古い手法として、sum(nested_list, []) を使う方法があります。
この方法は簡潔に見えますが、リストの結合を繰り返すたびに新しいリストを作成するため、計算量が O(n^2) となり非常に低速です。
現代の Python 開発においては、基本的にはリスト内包表記を使い、必要に応じて itertools を導入するのが正解です。
まとめ
Python でリストをフラット化する方法は多岐にわたりますが、状況に応じた最適な選択が求められます。
標準的な二次元リストであれば、シンプルかつ高速なリスト内包表記が第一候補となります。
メモリ消費が懸念される大規模なデータ処理には、itertools.chain.from_iterable を使用してください。
構造が複雑で予測できない場合は、再帰的なジェネレータ関数を作成することで、あらゆる深さに対応可能です。
それぞれのコードの挙動を正しく理解し、パフォーマンスと可読性のバランスが取れた実装を心がけましょう。
