【问题标题】:Flattening a list recursively [duplicate]递归展平列表[重复]
【发布时间】:2012-09-10 10:35:32
【问题描述】:

可能重复:
Flatten (an irregular) list of lists in Python

我在使用 python 递归展平列表时遇到问题。我已经看到了许多需要列表理解的方法和各种需要导入的方法,但是我正在寻找一种非常基本的方法来递归地展平不使用任何 for 循环的不同深度的列表。 我进行了一系列测试,但是有两个我无法通过

flatten([[[[]]], [], [[]], [[], []]]) # empty multidimensional list
flatten([[1], [2, 3], [4, [5, [6, [7, [8]]]]]]) # multiple nested list

我的代码

def flatten(test_list):
    #define base case to exit recursive method
    if len(test_list) == 0:
       return []
    elif isinstance(test_list,list) and type(test_list[0]) in [int,str]:
        return [test_list[0]] + flatten(test_list[1:])
    elif isinstance(test_list,list) and isinstance(test_list[0],list):
        return test_list[0] + flatten(test_list[1:])
    else:
        return flatten(test_list[1:])

我将不胜感激。

【问题讨论】:

  • @Anthony -- 检查假定的副本。我认为您的问题已经得到很好的回答。
  • 我问了一个类似的问题here,给出的答案没有使用任何导入或理解。它确实有一个 for 循环。这个要求有什么特别的原因吗?

标签: python list recursion nested


【解决方案1】:
li=[[1,[[2]],[[[3]]]],[['4'],{5:5}]]
flatten=lambda l: sum(map(flatten,l),[]) if isinstance(l,list) else [l]
print flatten(li)

【讨论】:

  • sum的目的是什么?
  • @TomHale sum(list, list) 连接它们(列表)。
【解决方案2】:

好吧,如果你想要一个 lisp 的方式,让我们拥有它。

atom = lambda x: not isinstance(x, list)
nil  = lambda x: not x
car  = lambda x: x[0]
cdr  = lambda x: x[1:]
cons = lambda x, y: x + y

flatten = lambda x: [x] if atom(x) else x if nil(x) else cons(*map(flatten, [car(x), cdr(x)]))

【讨论】:

  • 大声笑,我喜欢你如何将最后一位从 flatten(x[0]) + flatten(x[1:]) 更改为 cons(*map(flatten, [car(x), cdr(x)]))。您能否为旧时添加更多括号?
【解决方案3】:

这可以处理你的两种情况,我认为可以解决一般情况,没有任何 for 循环:

def flatten(S):
    if S == []:
        return S
    if isinstance(S[0], list):
        return flatten(S[0]) + flatten(S[1:])
    return S[:1] + flatten(S[1:])

【讨论】:

  • 谢谢@Mu Mind——这正是我所缺少的——将列表的第一部分以及剩余部分返回给递归函数。一直在努力,所以非常感谢
  • 我认为第一个 if 子句应该是:如果 S == [] 或 len(S) == 1,因为如果那么长度为 1,则第二个或第三个返回与 S[1 连接: ] 会抛出一个超出范围的索引....
  • @RvL 试试看。 =) 切片 [:1][1:] 对于单项列表是完全合理的,无论如何切片永远不会引发 IndexError。
【解决方案4】:

这是一个没有任何循环或列表推导的可能解决方案,只使用递归:

def flatten(test_list):
    if isinstance(test_list, list):
        if len(test_list) == 0:
            return []
        first, rest = test_list[0], test_list[1:]
        return flatten(first) + flatten(rest)
    else:
        return [test_list]

【讨论】:

  • 嗯,尝起来像 Lisp。这实际上与我们当年在 Scheme 中编写的代码相同......
  • 这也将为flatten(0)返回[0]。不知道这是赞成还是反对......
  • 考虑到问题中的要求(没有循环),这是一个很好的答案,但可能值得注意的是,性能会非常糟糕。 Python 的list 类型不是链表,而是类似数组的东西。每次在递归步骤flatten(first) + flatten(rest) 中加入两个列表时,代码都会复制两个列表的所有内容。我认为需要 O(N^2) 时间来生成长度为 N 的输出列表。
  • @tobias_k 谢谢你的帮助 - 我从调试代码中知道它失败了但是我从没想过将列表的第一部分作为参数返回给递归函数 return flatten(test_list[0]) + flatten(test_list[1:]) 我是当 test_list 为 [[4, [5, [6, [7, [8]]]]]] 时失败,但无法完成下一步。我了解递归效率有多低,但是这是递归练习。否则我不会这样做。谢谢大家
  • 在 Python3 中,代码为 def flatten1(test_list): if isinstance(test_list, list): if len(test_list) == 0: return [] first, rest = test_list[0], test_list[1:] return chain(flatten(first),flatten(rest)) else: return [test_list]
猜你喜欢
  • 2011-07-21
  • 2013-11-17
  • 1970-01-01
  • 2020-07-28
  • 2016-05-27
  • 2018-06-24
  • 1970-01-01
  • 1970-01-01
  • 2017-05-15
相关资源
最近更新 更多