10

コンパイラ パッケージの非推奨以降、ネストされたリストを平坦化するための推奨される方法は何ですか?

>>> from compiler.ast import flatten
>>> flatten(["junk",["nested stuff"],[],[[]]])
['junk', 'nested stuff']

リストの平坦化にはいくつかのスタックオーバーフローの答えがあることを知っていますが、これを行うための「1つ、できれば1つだけの明白な方法」であるpythonicの標準パッケージを望んでいます。

4

7 に答える 7

12

itertools.chainネストされた反復可能な 1 つのレベルを平坦化するための最良のソリューションです。純粋な Python ソリューションと比較して非常に効率的です。

とはいえ、すべてのイテラブルで機能するため、たとえば文字列をフラット化することを避けたい場合は、いくつかのチェックが必要です。

同様に、任意の深さまで魔法のように平らになることもありません。とはいえ、一般に、このような汎用的なソリューションは必要ありません。代わりに、そのような方法でフラット化する必要がないように、データを構造化したままにしておくことが最善です。

編集:任意の平坦化を行う必要がある場合、これが最善の方法であると主張します:

import collections

def flatten(iterable):
    for el in iterable:
        if isinstance(el, collections.Iterable) and not isinstance(el, str): 
            yield from flatten(el)
        else:
            yield el

basestring2.x ではstr、3.3 より前のfor subel in flatten(el): yield el代わりにを使用することを忘れないでください。yield from flatten(el)

コメントで述べたように、これは核の選択肢であり、解決するよりも多くの問題を引き起こす可能性が高いと私は主張します. 代わりに、出力をより規則的にし (たとえば、1 つの項目を含む出力でも 1 つの項目のタプルとして出力します)、最後にすべてではなく、導入された場所で 1 レベルずつ定期的に平坦化することをお勧めします。

これにより、より論理的で読みやすく、コードの操作が容易になります。当然、この種のフラット化を行う必要がある場合があります(データがどこから来ているかをいじることができない場合は、構造化されていない形式で取得するしかありません)。その場合、この種の解決策が必要になるかもしれませんが、一般的には、それはおそらく悪い考えです。

于 2013-04-23T18:39:16.147 に答える
6

あなたが述べた関数は、ネストされたリストを取り、それを新しいリストにフラット化します。

任意にネストされたリストを新しいリストにフラット化するために、これは期待どおりに Python 3 で機能します。

import collections
def flatten(x):
    result = []
    for el in x:
        if isinstance(x, collections.Iterable) and not isinstance(el, str):
            result.extend(flatten(el))
        else:
            result.append(el)
    return result

print(flatten(["junk",["nested stuff"],[],[[]]]))  

版画:

['junk', 'nested stuff']

同じことを行うジェネレーターが必要な場合:

def flat_gen(x):
    def iselement(e):
        return not(isinstance(e, collections.Iterable) and not isinstance(e, str))
    for el in x:
        if iselement(el):
            yield el
        else:
            for sub in flat_gen(el): yield sub

print(list(flat_gen(["junk",["nested stuff"],[],[[[],['deep']]]]))) 
# ['junk', 'nested stuff', 'deep']

Python 3.3 以降では、ループの代わりにyield fromを使用します。

def flat_gen(x):
    def iselement(e):
        return not(isinstance(e, collections.Iterable) and not isinstance(e, str))
    for el in x:
        if iselement(el):
            yield el
        else:
            yield from flat_gen(el)   
于 2013-04-23T18:49:09.150 に答える
1

任意のネストを持つリストの組み込みメソッドはありませんが、次のようなものです...

def flatten(l):
    for i in l:
        if isinstance(i, (list, tuple)):
            for ii in flatten(i):
                yield ii
        else:
            yield i

>>> l = ["junk",["nested stuff"],[],[[]]]
>>> list(flatten(l))
['junk', 'nested stuff']

...リストとタプルで機能します。式で使用できるオブジェクトをサポートしたい場合は、for item in objectおそらくこのようなダックタイピングを使用するのが最善です...

def flatten(l):
    for i in l:
        if isinstance(i, (str, bytes)):
            yield i
        else:
            try:
                for ii in flatten(i):
                    yield ii
            except TypeError:
                yield i

>>> l = ["junk",["nested stuff"],[],[[]]]
>>> list(flatten(l))
['junk', 'nested stuff']

isinstance(el, Iterable)...これは、このようないくつかのケースに対処できないため、check よりもわずかに堅牢です...

class Range10:
    def __getitem__(self, index):
        if index >= 10:
            raise IndexError
        return index

>>> import collections
>>> r10 = Range10()
>>> isinstance(r10, collections.Iterable)
False
>>> list(Range10())
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
于 2013-04-23T18:49:52.307 に答える
1

while-chain楽しみのためだけに、私の醜い解決策:

from collections import Iterable
from itertools import chain

def flatten3(seq, exclude=(str,)):
    sub = iter(seq)
    try:
        while sub:
            while True:
                j = next(sub)
                if not isinstance(j, Iterable) or isinstance(j, exclude):
                    yield j
                else:
                    sub = chain(j, sub)
                    break
    except StopIteration:
        return
于 2013-04-23T19:48:06.173 に答える
0

再帰用に構築: Python 3.6

def flatten(lst):
    """Flattens a list of lists"""
    return [subelem for elem in lst 
                    for subelem in elem]

リストでタイプを定義し、組み込みの any を使用してチェックします

于 2018-06-26T20:22:36.697 に答える