再帰的である必要はありません。実際、関数呼び出しに伴うオーバーヘッドのために、反復ソリューションの方が高速なことがよくあります。これは、私がしばらく前に書いた反復バージョンです。
def flatten(items, seqtypes=(list, tuple)):
for i, x in enumerate(items):
while i < len(items) and isinstance(items[i], seqtypes):
items[i:i+1] = items[i]
return items
この特定の実装のパフォーマンスをテストしていませんが、多くのメモリを移動する可能性があるすべてのスライス割り当てのために、おそらくそれほど優れていません。それでも、再帰的でなければならない、またはそのように書く方が簡単だと思い込まないでください。
この実装には、再帰的なソリューションが常に行うように、コピーを返すのではなく、リストを「その場で」フラット化するという利点があります。これは、メモリが不足している場合に役立ちます。フラット化されたコピーが必要な場合は、フラット化するリストの浅いコピーを渡すだけです。
flatten(mylist) # flattens existing list
newlist = flatten(mylist[:]) # makes a flattened copy
また、このアルゴリズムは再帰的ではないため、Python の再帰制限によって制限されません。ただし、これが事実上機能することはないと確信しています。
try
2021 編集: リストの末尾のチェックは/で処理したほうがよいとexcept
思います。なぜなら、それは 1 回しか行われず、メイン ループからテストを除外するとパフォーマンスが向上する可能性があるためです。それは次のようになります。
def flatten(items, seqtypes=(list, tuple)):
try:
for i, x in enumerate(items):
while isinstance(items[i], seqtypes):
items[i:i+1] = items[i]
except IndexError:
pass
return items
アクセスする代わりに、x
返された byを使用するようにさらに微調整すると、これが得られます。これは、リストのサイズと構造に応じて、最初のバージョンよりもわずかにまたは大幅に高速です。enumerate
items[i]
def flatten(items, seqtypes=(list, tuple)):
try:
for i, x in enumerate(items):
while isinstance(x, seqtypes):
items[i:i+1] = x
x = items[i]
except IndexError:
pass
return items