【问题标题】:On Finding the Maximum Depth of an Arbitrarily Nested List关于寻找任意嵌套列表的最大深度
【发布时间】:2015-05-25 04:53:08
【问题描述】:

我目前正在使用 Python 中的递归函数,但遇到了麻烦。如题,问题是返回任意嵌套列表的最大深度。

这是我目前所拥有的:

def depthCount(lst):
    'takes an arbitrarily nested list as a parameter and returns the maximum depth to which the list has nested sub-lists.'

    var = 0

    if len(lst) > 0:

        if type(lst[0]) == list:
            var += 1
            depthCount(lst[1:])

        else:
            depthCount(lst[1:])

    else:
        return var

我觉得问题出在我的递归调用上(这可能很明显)。当列表到达末尾时,它确实会返回 var ,但是当我有一个非空列表时,事情就会出错。什么都没有返回。

我切错了吗?我应该在递归调用中的切片之前做些什么吗?

问题也可能与我的基本情况有关。

【问题讨论】:

  • if len(lst) > 0: 块中的任何地方都没有return var 时,为什么会返回一些东西?
  • 即使你想在list 上进行类型切换,这样你就不会递归到字符串、元组、字典等,你真的想要防止递归到list 的子类吗? ?如果没有,请使用isinstance(lst[0], list)
  • 您能否更具体地说明您的“嵌套列表”是什么样的?它们是否包含列表以外的任何内容,还是仅包含 [[[], []], [], [[]]] 之类的内容?

标签: python recursion


【解决方案1】:

如果它们只是嵌套列表,例如[[[], []], [], [[]]],这是一个不错的解决方案:

def depthCount(lst):
    return 1 + max(map(depthCount, lst), default=0)

如果您不使用 Python 3.4,您可以使用以下细微变化,其中引入了 default 参数:

def depthCount(lst):
    return len(lst) and 1 + max(map(depthCount, lst))

它们的计数方式也不同。第一个认为空列表为深度 1,第二个为深度 0。第一个很容易适应,不过,只需将默认值设为 -1。


如果它们不只是嵌套列表,例如 [[[1], 'a', [-5.5]], [(6,3)], [['hi']]]),以下是对此的改编:

def depthCount(x):
    return 1 + max(map(depthCount, x)) if x and isinstance(x, list) else 0

def depthCount(x):
    return int(isinstance(x, list)) and len(x) and 1 + max(map(depthCount, x))

确保您了解后者的工作原理。如果你还不知道,它会教你and 如何在 Python 中工作:-)


接受“纯递归”挑战:

def depthCount(x, depth=0):
    if not x or not isinstance(x, list):
        return depth
    return max(depthCount(x[0], depth+1),
               depthCount(x[1:], depth))

当然,额外的参数有点难看,但我认为没关系。

【讨论】:

  • 是的,这也有效。基本上,您没有传递标志,而是将其更改为下推而不是上推递归,并将下推深度合并到标志中。这是个好主意;除非我尝试编写尾递归代码(这显然不是),否则我通常不会想到下推,但这里没有理由不这样做。
【解决方案2】:

当列表到达末尾时它确实会返回 var,但是当我有一个非空列表时,事情就会出错。什么都没有返回。

那是因为您没有 return 语句,除了空列表的 else 基本情况。如果你在函数末尾没有碰到return,就意味着函数返回None

但除此之外,您还有另一个问题。你开始var = 0,然后可能在做var += 1……但你没有将它传递给递归调用,或者使用递归调用的任何结果。所以递归调用根本没有用处。

你的意思可能是这样的:

def depthCount(lst):
    'takes an arbitrarily nested list as a parameter and returns the maximum depth to which the list has nested sub-lists.'

    if len(lst) > 0:

        if type(lst[0]) == list:
            return 1 + depthCount(lst[1:])
        else:
            return depthCount(lst[1:])

    else:
        return 0

但这实际上仍然不正确。列表的深度计数比其最深元素的深度计数多 1。仅仅检查它的 second 元素对你没有任何好处。你需要检查他们的所有。所以,你真正想要的是这样的:

def depthCount(lst):
    'takes an arbitrarily nested list as a parameter and returns the maximum depth to which the list has nested sub-lists.'
    if isinstance(lst, list):
        return 1 + max(depthCount(x) for x in lst)
    else:
        return 0

如果您想用 second 层递归替换该迭代 for x in lst,当然可以,但我看不出有什么好的理由这样做;它只是无缘无故地使代码更加复杂。例如:

def max_child_count(lst):
    if lst:
        return max(depth_count(lst[0]), max_child_count(lst[1:]))
    else:
        return 0

def depth_count(lst):
    if isinstance(lst, list):
        return 1 + max_child_count(lst)
    else:
        return 0

可能仍然不正确。它绝对是正确的,例如,[1, [2,3], [4, [5]]]。但是它应该为[] 做什么?从你的问题我看不出来。如果它应该返回01,您显然需要适当地更改if。如果这是非法输入,那么它已经在做正确的事情了。 (并且应该还回答了它应该做什么的问题,例如,[[[], []], [], [[]]],但请确保您也考虑过这种情况。)

【讨论】:

  • 您的第一个 depthCount()[] 上失败。 ValueError: max() arg is an empty sequence。是错误还是功能?
  • @sobolevn:我不确定;你得问写作业的人。如果它是一个错误,当然很容易修复。如果正确答案应该是0,只需将条件更改为if isinstance(lst, list) and lst:。如果它应该是不同的东西,你会想要不同的改变。 :)
【解决方案3】:

因此,本质上,您所指的数据结构是k-ary 树,也称为 n 叉树,具有任意分支。这是确定最大值的代码。具有任意分支的 n 叉树的深度。

def maxdepth(tree):
    if isleaf(tree):
        return 1
    maximum = 0
    for child in children(tree):
        depth = maxdepth(child)
        if depth > maximum:
            maximum = depth
    return maximum + 1

您可以通过不同的测试输入here查看运行代码。

【讨论】:

  • 感谢 Siddharth,如果您必须在不使用循环的情况下解决这个问题?
  • 纯递归...让我想想。
  • @Typhon:要使这个完全递归,你必须用递归替换 both 循环。最易读的方法是使用两个相互递归的函数,就像我回答的结尾一样。但您可能实际上并不想这样做。
  • 我必须同意@abarnert 关于这一点。如果您想纯粹递归地执行此操作,则必须进行相互递归。 :)
  • @SiddharthShukla:嗯,你可以用一个函数来做,通过使用一个标志来有效地编码一个两态状态机......但我认为它会降低可读性,仅此而已。
猜你喜欢
  • 2016-06-18
  • 1970-01-01
  • 2018-04-14
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
  • 2013-08-22
相关资源
最近更新 更多