On Finding the Maximum Depth of an Arbitrarily Nested List

生来就可爱ヽ(ⅴ<●) 提交于 2021-02-19 01:17:26

问题


I'm currently working with a recursive function in Python, and I've run into a wall. As titled, the problem is to return the maximum depth of an arbitrarily nested list.

Here is what I have so far:

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

I feel that the problem is with my recursive calls (this may be obvious). It will indeed return var when the list has reached the end, but when I have a nonempty list, things go awry. Nothing is returned at all.

Am I slicing wrong? Should I be doing something before the slice in the recursive call?

The problem may also be with my base case.


回答1:


If they are just nested lists, e.g., [[[], []], [], [[]]], here's a nice solution:

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

Here's a slight variation you could use if you don't use Python 3.4, where the default argument was introduced:

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

They also differ by how they count. The first considers the empty list to be depth 1, the second to be depth 0. The first one is easy to adapt, though, just make the default -1.


If they're not just nested lists, e.g., [[[1], 'a', [-5.5]], [(6,3)], [['hi']]]), here are adaptions to that:

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

Make sure you understand how the latter one works. If you don't know it yet, it'll teach you how and works in Python :-)


Taking the "purely recursive" challenge:

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

Granted, the extra argument is slightly ugly, but I think it's ok.




回答2:


It will indeed return var when the list has reached the end, but when I have a nonempty list, things go awry. Nothing is returned at all.

That's because you have no return statement, except in the else base case for an empty list. And if you fall off the end of the function without hitting a return, that means the function returns None.

But you have another problem on top of that. You're starting var = 0, then possibly doing var += 1… but you're not passing that down into the recursive calls, or using any result from the recursive calls. So the recursive calls have no useful effect at all.

What you probably meant is something like this:

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

But this still isn't actually right. The depth count of a list is 1 more than the depth count of its deepest element. Just checking its second element won't do you any good; you need to check all of them. So, what you really want is something like this:

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

If you want to replace that iterative for x in lst with a second layer of recursion, of course you can, but I can't see any good reason to do so; it just makes the code more complicated for no reason. For example:

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

This may still not be right. It definitely does the right thing for, e.g., [1, [2,3], [4, [5]]]. But what should it do for, say, []? I can't tell from your question. If it should return 0 or 1, you'll obviously need to change the if appropriately. If that's illegal input, then it's already doing the right thing. (And that should also answer the question of what it should do for, e.g., [[[], []], [], [[]]], but make sure you think through that case as well.)




回答3:


So, essentially, the data structure that you're referring to is a k-ary tree, also known as n-ary tree, with arbitrary branching. Here's the code for determining the max. depth of a n-ary tree with arbitrary branching.

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

You can see the code in action with different test inputs here.



来源:https://stackoverflow.com/questions/30427268/on-finding-the-maximum-depth-of-an-arbitrarily-nested-list

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!