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

时间:2018-01-15 11:28:06

标签: python python-3.x list recursion generator

我正在玩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

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

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

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

1 个答案:

答案 0 :(得分:5)

所以,你正试图压扁一个列表。你已走上正轨,但你犯了几个错误。他们在这里。

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

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

  3. 最后,在except中,您需要yield element,而不是toflatten。不要产生整个清单。

  4. 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