Python 3replace为不推荐的compiler.ast flatten函数

自从编译器软件包弃用以来, 推荐使用嵌套列表的方法是什么?

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

我知道列表展平有几个堆栈溢出的答案,但我希望pythonic,标准的包,“一个,最好只有一个,明显的方式”来做到这一点。

你声明的函数需要一个嵌套的列表,并将其变成一个新的列表。

为了将任意嵌套的列表平铺到新的列表中,您可以像预期的那样使用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而不是循环:

 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) 

itertools.chain是平坦化任何嵌套的可迭代的一个级别的最佳解决scheme – 与任何纯Python解决scheme相比,它是高效的。

也就是说,它可以在所有的迭代器上工作,所以如果你想避免它把string弄平,就需要一些检查。

同样,它也不会神奇地变成任意深度。 这就是说,一般来说,这种通用的解决scheme并不是必需的 – 相反,最好保持数据结构化,这样就不需要以这种方式展平。

编辑:我会争辩说,如果一个人必须做任意展平,这是最好的方法:

 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 

记得在2.x中使用basestringfor subel in flatten(el): yield el使用basestring for subel in flatten(el): yield el yield from flatten(el) 3.3版本之前的for subel in flatten(el): yield el而不是yield from flatten(el)

正如评论中指出的那样,我认为这是核select,可能会造成比解决问题更多的问题。 相反,最好的办法是让你的输出更加规整(例如,包含一个项目的输出仍然将其作为一个项目元组),并且在引入它的地方进行定期展平,而不是在最后。

这将产生更多的逻辑,可读性更强,更容易使用代码。 当然,有些情况下,你需要做这种扁平化(如果数据来自某个你无法琢磨的地方,所以你别无select,只能采用结构不良的格式),在这种情况下,这种解决scheme可能是需要的,但一般来说,这可能是一个坏主意。

你可以使用funcy库中的flatten函数:

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

您也可以明确指定要遵循的值:

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

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

我的丑陋while-chain解决scheme,只是为了好玩:

 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 

有没有内置的方法为任意嵌套的列表,但是像这样的…

 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 objectexpression式中的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]