web-dev-qa-db-ja.com

Pythonで任意にネストされたリストをフラット化する最速の方法は何ですか?

可能性のある複製:
Pythonでの浅いリストのフラット化
Pythonのリストのフラット(不規則)リスト

EDIT:問題はhowではなく-これは 議論 他の 質問 -問題は、fastestメソッドですか?

以前に解決策を見つけましたが、任意の長さの他のリストを含むリストを平坦化するのが最も速い解決策は何だろうと思っています。

例えば:

[1, 2, [3, 4, [5],[]], [6]]

になるでしょう:

[1,2,3,4,5,6]

レベルは無限にあります。一部のリストオブジェクトは文字列にすることができますが、出力リスト内の連続した文字にフラット化することはできません。

45
Rory

文字列に優しい再帰的なアプローチを次に示します。

nests = [1, 2, [3, 4, [5],['hi']], [6, [[[7, 'hello']]]]]

def flatten(container):
    for i in container:
        if isinstance(i, (list,Tuple)):
            for j in flatten(i):
                yield j
        else:
            yield i

print list(flatten(nests))

戻り値:

[1, 2, 3, 4, 5, 'hi', 6, 7, 'hello']

これは、速度やオーバーヘッドの使用を保証するものではありませんが、役に立つと思われる再帰的なソリューションを示しています。

55
hexparrot

haveは再帰的ではありません。実際、関数呼び出しに伴うオーバーヘッドのため、反復ソリューションの方が高速になることがよくあります。しばらく前に書いた反復バージョンは次のとおりです。

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再帰制限によって制限されません。ただし、これは事実上決して機能しません。

18
kindall

この関数は、再帰を使用せずに、ネストされた反復可能なコンテナをすばやくフラット化できる必要があります。

import collections

def flatten(iterable):
    iterator = iter(iterable)
    array, stack = collections.deque(), collections.deque()
    while True:
        try:
            value = next(iterator)
        except StopIteration:
            if not stack:
                return Tuple(array)
            iterator = stack.pop()
        else:
            if not isinstance(value, str) \
               and isinstance(value, collections.Iterable):
                stack.append(iterator)
                iterator = iter(value)
            else:
                array.append(value)

約5年後、この問題についての私の意見は変わりました。これはさらに使いやすいものです。

def main():
    data = [1, 2, [3, 4, [5], []], [6]]
    print(list(flatten(data)))


def flatten(iterable):
    iterator, sentinel, stack = iter(iterable), object(), []
    while True:
        value = next(iterator, sentinel)
        if value is sentinel:
            if not stack:
                break
            iterator = stack.pop()
        Elif isinstance(value, str):
            yield value
        else:
            try:
                new_iterator = iter(value)
            except TypeError:
                yield value
            else:
                stack.append(iterator)
                iterator = new_iterator


if __== '__main__':
    main()
8
Noctis Skytower