Pythonにリスト用の「フラット化」関数がないのはなぜですか?


39

ErlangとRubyの両方には、配列を平坦化するための関数が付属しています。言語に追加するためのこのようなシンプルで便利なツールのようです。これを行うことができます:

>>> mess = [[1, [2]], 3, [[[4, 5]], 6]]
>>> mess.flatten()
[1, 2, 3, 4, 5, 6]

あるいは:

>>> import itertools
>>> mess = [[1, [2]], 3, [[[4, 5]], 6]]
>>> list(itertools.flatten(mess))
[1, 2, 3, 4, 5, 6]

代わりに、Pythonでは、配列をゼロから平坦化するための関数を記述するという問題を経験する必要があります。これはばかげているように見えますが、配列の平坦化はよくあることです。これは、2つの配列を連結するためのカスタム関数を作成する必要があるようなものです。

私はこれを無駄にグーグルで検索したので、ここで質問しています。Python 3のような成熟した言語に10万のさまざまなバッテリーが含まれているのに、配列を平坦化する簡単な方法が提供されない特別な理由はありますか?そのような機能を含めるという考え方は、ある時点で議論され、拒否されましたか?


2
@detly:複数のクエリを使用してさまざまなソースからデータを取得するときに、最近フラット化が失敗することがありました。各クエリは辞書のリストを返すので、最終的には辞書のリストに変換する辞書のリストのリストがあります。ループ+を使用しましたextendが、flattenの方がはるかにエレガントでした。ただし、このパターンが標準ライブラリでフラット化されていることを正当化するのに十分なほど一般的である場合、私は負けです。
ジョルジオ14

4
「つまり、データの構造を誤って変更するバグをコードに導入した場合を考えてみてください。flattenは動作しますが、完全に間違った結果を生成します。」:これが静的型付け言語が好きな理由の1つです。;-)
ジョルジオ14


2
@BryanOakley以前のコメントも参照してください(複数レベルのリストではありませんが、一般的にフラット化が一般的です
Izkata 14

3
Mathemaicaに組み込まれており、私はそれを広く使用しています。
アレキサンダーソン

回答:


34

flatten標準ライブラリに追加される関数の提案は、時々python-devおよびpython-ideasメーリングリストに表示されます。Python開発者は通常、次の点で対応します。

  1. 1レベルのフラット化(反復可能な反復可能オブジェクトを単一の反復可能に変換する)は、単純な1行の式で(x for y in z for x in y)あり、いずれの場合も名前で標準ライブラリに既に存在しitertools.chain.from_iterableます。

  2. 汎用マルチレベルフラット化の使用例は何ですか?これらは、関数を標準ライブラリに追加するのに本当に魅力的ですか?

  3. 汎用マルチレベルフラット化は、フラット化するタイミングと放置するタイミングをどのように決定しますか?「繰り返し可能なインターフェイスをサポートするものはすべて平坦化する」などのルールは機能すると思うかもしれませんが、それはの無限ループにつながるでしょうflatten('a')

たとえば、Raymond Hettingerを参照してください。

comp.lang.pythonで悪心について議論されています。人々は、ささいな解決策をまだ持っていない正当なユースケースを見つけるよりも、flattenの独自のバージョンを書くことを楽しんでいるようです。

汎用フラットナーには、アトミックなものとさらに細分化できるものを通知する何らかの方法が必要です。また、ノードおよびリーフ(事前順序、事後順序、順序のトラバーサルなど)にデータがあるツリー状のデータ構造を持つ入力をカバーするためにアルゴリズムをどのように拡張する必要があるかは明らかではありません。


明確に言うと、これは1レベルflatten関数をとして定義できることを意味しlambda z: [x for y in z for x in y]ます。
クリストファーマーティン

1
「汎用フラットナーには、アトミックなものとさらに細分化できるものを伝えるための何らかの方法が必要です。」:これは、OOPを使用して解決できる問題のように聞こえます。各オブジェクトにはflattenメソッドがあります。flattenオブジェクトがコンポジットの場合、このメソッドの実装はそのサブコンポーネントを再帰的に呼び出す必要があります。残念ながら、私の知る限り、すべての値がPythonのオブジェクトではありません。ただし、Rubyでは動作するはずです。
ジョルジオ

1
継続的な「for in for in」ではなく、1レベルのフラット化のフラット化ヘルパーは、すでに十分なIMOケースです。読みやすい
dtc

2
@Giorgio Pythonはそのようなメソッドを避けています。プロトコルが優先されますが、OOP設計よりもはるかにスムーズに作業できることがわかります。多くの場合、まったく実装する必要さえないからです。
jpmc26

8

そのようなメソッドが付属していますが、フラット化とは呼びません。「チェーン」と呼ばれます。イテレータを返すので、list()関数を使用してリストに戻す必要があります。*を使用したくない場合は、2番目の「from_iterator」バージョンを使用できます。Python 3 でも同じように機能します。リスト入力がリストのリストでない場合、失敗します。

[[1], [2, 3], [3, 4, 5]] #yes
[1, 2, [5, 6]] #no

compiler.astモジュールには一度にflattenメソッドがありましたが、これは2.6で非推奨になり、3.0で削除されました。任意にネストされたリストに必要な任意の深さ再帰は、Pythonの保守的な最大再帰深さではうまく機能しません。コンパイラの削除の理由は、それが混乱であることが主な原因でした。コンパイラはastに変わりましたが、flattenは残されました。

numpyの配列とそのライブラリを平坦化することで、任意の深さを実現できます。


chain.from_iteratorあなたが言ったように、この関数は二次元リストを平坦化するためにのみ使用できます。actualy受け付け平ら機能、任意のネストされたリストを返す1次元リストの量は、まだ(少なくとも私の意見で)例がたくさんで大規模有用であろう
Hubro

2
@Hubro:「多くの場合」— 6に名前を付けることができますか?
ガレスリース

1
@GarethRees:私はここにいくつかの例を与えた:programmers.stackexchange.com/questions/254279/...を
Hubro

また、他の言語が実際に説明されている非常に簡単な方法でリストをフラット化する機能を実際に提供している場合、それはその単純な機能をPythonに追加することをサポートする最も説得力のある議論の1つであると主張するまで行きます。
ボボート

イテレータまたはジェネレータを返しますか?
jpmc26

-1

...たぶん自分で書くのはそれほど難しくないから

def flatten(l): return flatten(l[0]) + (flatten(l[1:]) if len(l) > 1 else []) if type(l) is list else [l]

...そして、あなたが望むすべてを平らにします:)

>>> flatten([1,[2,3],4])
[1, 2, 3, 4]
>>> flatten([1, [2, 3], 4, [5, [6, {'name': 'some_name', 'age':30}, 7]], [8, 9, [10, [11, [12, [13, {'some', 'set'}, 14, [15, 'some_string'], 16], 17, 18], 19], 20], 21, 22, [23, 24], 25], 26, 27, 28, 29, 30])
[1, 2, 3, 4, 5, 6, {'age': 30, 'name': 'some_name'}, 7, 8, 9, 10, 11, 12, 13, set(['set', 'some']), 14, 15, 'some_string', 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
>>> 

8
askerは次のことを認識しています。「Pythonでは、配列をゼロから平坦化するための関数を記述する手間をかけなければなりません」。これは、「これは私には馬鹿げているように見えます。配列を平坦化することはよくあることです。2つの配列を連結するためのカスタム関数を書かなければならないようなものです。」
-gnat

1
トピック外...しかし、超クール:-) !!
SeF

この答えは、関数を自分でコーディングする方法を知らなかったので、OPが良い開発者ではないことをOPに伝えるようなものです。私は、これは便利なコードがあっても、オフトピック、質問時につまずく人のためのものですので、あなたがあなたの答えの始まりを変更示唆
フェデリコ・ボネリ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.