在python中递归地展平嵌套列表

Chu*_*ner 3 python recursion list generator python-3.x

我正在使用Python中的生成器,我正在尝试使用简单的递归方案来实现flatten-function.也就是说,一个函数将一个列表作为输入,该列表可能包含子列表,并输出一个只能在输入的原子元素上迭代的可迭代对象.

所以,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
Run Code Online (Sandbox Code Playgroud)

因此,它应检查其参数是否是可迭代对象.如果是这种情况,也可以对此对象进行递归.否则,将其作为原子元素.

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

为什么会这样?特别是; 为什么它甚至没有对此输入执行递归函数调用?(我使用的是Python 3.5)

cs9*_*s95 6

所以,你试图压扁一个列表.你走在正确的轨道上,但你犯了几个错误.他们来了.

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

  2. 在尝试中,你什么都不产生.只进行函数调用.你也应该从那里归还一些东西.yield from如果你有python3.3 +,我建议你.

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

def flatten(toflatten):    
   for element in toflatten:
       try:
           yield from flatten(element)
       except TypeError:
           yield element
Run Code Online (Sandbox Code Playgroud)

这给了,

>>> list(flatten([1,2,3,[4,5,6]]))
[1, 2, 3, 4, 5, 6]
Run Code Online (Sandbox Code Playgroud)

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


还有另一种方法:LYBL(在你跳跃之前看).它包括更谨慎,使用if语句,因此不会引发错误.

def flatten(toflatten):    
   for element in toflatten:
       if isinstance(element, list):
           yield from flatten(element)
       else:
           yield element
Run Code Online (Sandbox Code Playgroud)

哪个和以前一样,并给出,

>>> list(flatten([1,2,3,[4,5,6]]))
[1, 2, 3, 4, 5, 6]
Run Code Online (Sandbox Code Playgroud)

然而,这是有利的,因为yield from仅在子列表上调用生成器委托.我提到它也适用于字符串元素吗?

>>> list(flatten([1,2,3,[4,5,'abc']]))
[1, 2, 3, 4, 5, 'abc']
Run Code Online (Sandbox Code Playgroud)

请注意,在任何一种情况下,如果您有递归定义的列表,则无限递归的警告.例如,flatten这种输入会崩溃.

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

flatten(x)
Run Code Online (Sandbox Code Playgroud)

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

RuntimeError: maximum recursion depth exceeded
Run Code Online (Sandbox Code Playgroud)

  • @timgeb提到EAFP使用字符串失败,并且都使用递归列表失败.感谢您的评论! (2认同)