递归扁平化 python 中的嵌套列表



我正在玩弄Python中的生成器,并尝试使用简单的递归方案来实现扁平函数。也就是说,一个函数,它将可能包含子列表的列表作为输入,并输出仅迭代输入的原子元素的可迭代对象。

因此,print(list(flatten([1,2,3,[4,5,6]])))应该返回包含[1,2,3,4,5,6]的内容。

我的尝试如下:

def flatten(toflatten):
try:
for element in toflatten:
flatten(element)
except TypeError:
yield toflatten

因此,它应该检查其参数是否是可迭代对象。如果是这种情况,也递归于此对象。否则,将其作为原子元素生成

这不起作用,flatten([1,2,3,[4,5,6]])只返回一个空列表。

为什么会这样呢?特别是;为什么它甚至不对这个输入执行递归函数调用?(我正在使用Python 3.5)

因此,您正在尝试扁平化列表。你走在正确的轨道上,但你犯了几个错误。他们来了。

  1. 在循环移动try-except。使用代码时,如果为一个元素引发TypeError,则循环将停止运行。你不希望这种情况发生。

  2. 在尝试中,你一无所获。仅进行函数调用。您也应该从那里返回一些东西。如果你有python3.3+,我会推荐yield from

  3. 最后,在except中,你需要yield element,而不是toflatten。不要生成整个列表。

def flatten(toflatten):    
for element in toflatten:
try:
yield from flatten(element)
except TypeError:
yield element

这给了,

>>> list(flatten([1,2,3,[4,5,6]]))
[1, 2, 3, 4, 5, 6]

你已经使用了EAFP(比许可更容易请求宽恕),这很好。这是一种方法(实际上是我最喜欢的),但有一个缺点:这会在字符串上崩溃。


还有另一种方法:LYBL(在你跳跃之前先看看)。它包括更加谨慎,使用if语句,以免引发错误。

def flatten(toflatten):    
for element in toflatten:
if isinstance(element, list):
yield from flatten(element)
else:
yield element

它的工作原理与以前相同,并给出,

>>> list(flatten([1,2,3,[4,5,6]]))
[1, 2, 3, 4, 5, 6]

但是,这是有利的,因为yield from生成器委派仅在子列表上调用。我有没有提到它也适用于字符串元素?

>>> list(flatten([1,2,3,[4,5,'abc']]))
[1, 2, 3, 4, 5, 'abc']

请注意,无论哪种情况,如果您有递归定义的列表,则无限递归的警告。例如,flatten会因此类输入而崩溃。

x = [1, 2, 3]
x.append(x)
flatten(x)

您最终会收到运行时错误:

RuntimeError: maximum recursion depth exceeded

最新更新