def flattenList(toFlatten):
final=[]
for el in toFlatten:
if isinstance(el, list):
final.extend(flattenList(el))
else:
final.append(el)
return final
リストがどれだけ深くネストするかわからないときは、これが私がこれを行うために考えることができる唯一の方法です。
Pythonでのタイプチェックは避けてください。この場合、これは、タイプで区別する任意にネストされた構造を回避することを意味します。特定の属性を調べるなど、タイプチェック以外の方法でトラバースできる独自のノードタイプを作成できます。
1レベルまたは正確にnレベルを平坦化するには、を参照してitertools.chain.from_iterable
ください。
「機能的」とはどういう意味かわかりません。このコードはかなり機能的です。再帰を使用し(クレジットではありません!)、引数を変更しません。(厳密に言えば、リストを作成するために可変状態を使用しますが、それはPythonで行う方法です。
もう1つの機能属性は、遅延評価だと思います。このようにこれを実装することができます
def flatten(toFlatten):
for item in toFlatten:
if isinstance(item, list): # Ewww, typchecking
for subitem in flatten(item): # they are considering adding
yield subitem # "yield from" to the language
# to give this pattern syntax
else:
yield item
Pythonでは再帰が非常に制限されており(少なくとも、そのすべての主要な実装では)、通常、任意の深さで再帰を回避する必要があります。これ(およびすべての再帰コード)を書き直して反復を使用することは非常に可能です。これにより、これがよりスケーラブルになります(そして、機能が低下します。これは、FPには特に適していないPythonでは良いことです)。
reduce
この回答は、Pythonでこれを使用したくない理由を説明しています。
スニペットを検討してください
reduce(operator.add, [[1], [2], [3], [4], [5]])
これは何をする必要がありますか?
[1] + [2] => [1, 2]
[1, 2] + [3] => This makes a new list, having to go over 1, then 2, then 3. [1, 2, 3]
[1, 2, 3] + [4] => This has to copy the 1, 2, and 3 and then put 4 in the new list
[1, 2, 3, 4] + [5] => The length of stuff I have to copy gets bigger each time!
この2次動作は完全に回避できます。元のソリューション(および他の任意の数のソリューション)は、これらの中間コピーステップを形成しません。
itertoolsのドキュメントの下に、flatten()
関数があります
別のオプションがあります(ただし、何かが反復可能であり、したがって「アトム」ではないかどうかをテストするなど、型チェックよりもクリーンなものがある場合があります)。
def flatten(lst):
if not isinstance(lst,list):
return [lst]
else:
return reduce(lambda x,y:x+y,[flatten(x) for x in lst],[])
それはスキームのようなものに基づいています。