Python 3的更换过时compiler.ast扁平化功能(Python 3 replacemen

2019-08-31 23:18发布

什么是自扁平化嵌套列出了推荐的方式编译包的弃用 ?

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

我知道有对列表压扁了几个堆栈溢出的答案,但我希望能为Python化,标准包“一个,最好只有一种,明显的方式”来做到这一点。

Answer 1:

您所陈述的功能需要一个嵌套列表,而变平是进入一个新的列表。

扁平化的任意嵌套表到一个新的列表,你希望这个工程上的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和更高版本,使用产自代替循环:

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)   


Answer 2:

itertools.chain是压扁任何嵌套迭代一个级别的最佳解决方案-比任何纯Python的解决方案是高效的。

这就是说,它会在所有 iterables工作,所以如果你想避免这不上不下的字符串,例如一些检查是必需的。

同样,也不会神奇地变平到任意深度。 这就是说,一般不需要这样一个通用的解决方案 - 而不是它最好把你的数据结构使得它不需要以这种方式压扁。

编辑:我认为,如果一个人做任意的扁平化,这是最好的方法:

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

请记住,使用basestring在2.X过str ,并for subel in flatten(el): yield el ,而不是yield from flatten(el)预3.3。

正如在评论中指出,我认为这是核选择,并有可能导致更多的问题比它解决的。 相反,最好的办法是让你的输出更规则(包含一个项目输出仍然给它作为一个项目的元组,例如),并在那里被引入,而不是所有在最后一个级别做定期的扁平化。

这将产生更多的逻辑,可读性,也更容易与代码工作。 当然,有些情况下,你需要做这种扁平化的情况下(如果数据是从什么地方你不能惹的到来,所以你没有选择,只能把它的不良结构格式),在这种情况下,可能需要这样的解决方案,但在一般情况下,它可能是一个坏主意。



Answer 3:

您可以使用拼合从功能funcy库:

from funcy import flatten, isa
flat_list = flatten(your_list)

您也可以明确指定哪些值如下:

# Follow only sets
flat_list = flatten(your_list, follow=isa(set))

在偷看它的实现 ,如果你想要一个algorythm。



Answer 4:

我的丑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


Answer 5:

有与任意嵌套的列表中没有内置的方法,但是这样的事情...

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) ,因为它不会与某些情况下,如应对这一切?

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]


Answer 6:

专为递归:Python的3.6

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

定义你的类型的列表,然后使用任何内建的检查



文章来源: Python 3 replacement for deprecated compiler.ast flatten function