【问题标题】:Recursively flatten nested list in python在python中递归展平嵌套列表
【发布时间】:2018-06-24 00:41:49
【问题描述】:

我在 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)

【问题讨论】:

  • 首先,您希望flatten(element) 做什么?此行不返回/产生任何内容,也不改变任何数据结构,因此毫无意义。
  • 我知道如果您的最终目标是学习递归,这将无济于事,但请尝试 sum(yourlist,[]) 这将使您的列表变平。我建议最后返回您的清单。
  • @TomosWilliams 不,你不能连接整数和列表。
  • 你应该把try-except inside循环。
  • @timgeb 啊,你是对的!这正是我在扁平化列表时倾向于使用的技巧

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


【解决方案1】:

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

  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

【讨论】:

  • 您可能还需要考虑“不需要的”可迭代对象,例如字符串,如果您特别挑剔,可以考虑递归 toflatten 可迭代对象。 (例如toflatten = []; toflatten = [toflatten]
  • @timgeb 提到 EAFP 使用字符串失败,并且都使用递归列表失败。感谢 cmets!
  • 太棒了,所有问题都解决了,非常感谢! (我还不熟悉 yield-from 语句,这正是我想要的)
  • @ChuckSchuldiner Err,如果答案有用,将不胜感激marking it accepted。您可以通过单击答案旁边的灰色复选标记将其切换为绿色来做到这一点。表示您的问题已解决。谢谢。
  • 在跳跃之前看看你。
猜你喜欢
  • 2013-11-17
  • 2012-07-07
  • 2015-01-28
  • 1970-01-01
  • 1970-01-01
  • 2011-07-21
  • 2015-04-13
  • 2014-03-06
  • 1970-01-01
相关资源
最近更新 更多