【问题标题】:Traverse a nested list遍历一个嵌套列表
【发布时间】:2021-10-30 15:59:44
【问题描述】:

我正在尝试使用递归遍历列表并将其所有非列表元素和子列表的元素附加到唯一列表。

def refr(a_list):
    loo = []
    for item in a_list:
        if isinstance(item, list):
            refr(item)
        else:
            loo.append(item)
    return loo

print(refr([1, ['no', 'ok'], 'dang', 0]))

当我将 loo 定义为局部变量时,它只包含输入列表中不代表列表的元素。

# output

[1, 'dang', 0]

但是当定义为全局时,输出是正确的

# output

[1, 'no', 'ok', 'dang', 0]

为什么会这样?

【问题讨论】:

  • 这能回答你的问题吗? Flatten an irregular list of lists
  • @schwobaseggl 如果有重复,应该更符合“为什么递归调用的值被丢弃?”;这里的错误是没有使用递归调用refr(item)的返回值。除此之外,OP 似乎已经理解了如何遍历不规则列表的基本思想,并关闭他们的问题以将他们引荐给该列表不会有任何帮助。
  • @Stef True,这就是我的回答。顺便说一句,您可以添加更好的副本。字面上有几十个问题,比如“为什么递归函数返回 None”,而且总是这个问题。
  • @schwobaseggl 是的,我确实赞成您的回答。 “为什么递归函数返回 None”是我的第一直觉,但实际上,OP 的函数不返回 None。它总是返回一个列表;该列表只是省略了在递归调用期间计算的一​​些值。
  • 是的,骗子不必那么精确。我的链接骗子的答案和任何“递归无”问题的答案都将包含 OP 解决问题所需的所有信息。

标签: python python-3.x recursion


【解决方案1】:

使用来自documentextend(item)

list.extend(可迭代) 通过附加迭代中的所有项目来扩展列表。等价于 a[len(a):] = 可迭代。

试试这个:

def refr(a_list):
    loo = []
    for item in a_list:
        if isinstance(item, list):
            loo.extend(refr(item))
            # OR
            # loo += refr(item)
        else:
            loo.append(item)
    return loo

print(refr([1, ['no', 'ok'], 'dang', 0]))

输出:

[1, 'no', 'ok', 'dang', 0]

对于这个输入得到正确的输出:

print(refr([1, [['no', 'ok'], ['dang', 0]]]))
# [1, 'no', 'ok', 'dang', 0]

【讨论】:

    【解决方案2】:

    您没有使用递归调用的返回值:

    def refr(a_list):
        loo = []
        for item in a_list:
            if isinstance(item, list):
                loo += refr(item)
            else:
                loo.append(item)
        return loo
    

    或者,使用生成器函数,这通常就足够了,允许短路并且可以很容易地变成一个列表:

    def refr(a_list):
        for item in a_list:
            if isinstance(item, list):
                yield from refr(item)
            else:
                yield item
    

    从这里到单线不远,使用itertools.chain

    from itertools import chain
    
    def refr(a_list):
        return chain.from_iterable(refr(x) if isinstance(x, list) else [x] for x in a_list)
    
    [*refr([1, ['no', 'ok', [1, 2, [3]]], 'dang', 0])]
    # [1, 'no', 'ok', 1, 2, 3, 'dang', 0]
    

    【讨论】:

      【解决方案3】:

      因为本地 (!) loo 变量的范围是 refr 函数用于该特定调用。这意味着当您递归调用 refr 时,它将创建一个新的堆栈框架,其中包含另一个与第一个无关的空列表(它恰好具有相同的名称)。解决此问题的一种方法是在您的函数调用中添加一个累加器参数作为组合状态:

      def refr(a_list, acc=None):
          if acc is None:
              acc = []
          for item in a_list:
              if isinstance(item, list):
                  refr(item, acc)
              else:
                  acc.append(item)
          return acc
      
      refr([1, ['no', 'ok'], 'dang', 0])
      

      给予

      [1, 'no', 'ok', 'dang', 0]
      

      【讨论】:

      猜你喜欢
      • 2019-08-22
      • 2015-05-16
      • 1970-01-01
      • 2016-09-18
      • 2015-12-06
      • 2021-09-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多