展平后检索列表的长度

时间:2014-06-29 20:49:39

标签: python list recursion

我已经看到了一些关于列表展平的问题,我想知道如何检索展平列表的长度而不实际展平它。我的清单可以任意深入。

案例1:

输入:

[[[1, 2], 3], 4]

输出:

4

案例2:

输入:

[[[[1, 2], [3, 4]], 5], [6, 7]]

输出:

7

这是一个递归实现:

def flattenlen(a):
    total = 0
    for i in range(len(a)):
        if type(a[i]) == list:
            total += flattenlen(a[i])
        else:
            total += 1
    return total

print flattenlen([[[[1, 2], [3, 4]], 5], [6, 7]])

输出:

7

有没有人有封闭式解决方案?是否有内置方法或库来实现这一目标?我错过了一种更有效的方法吗?

1 个答案:

答案 0 :(得分:1)

您无需构建单独的列表即可轻松完成此操作:

def flattenlen(a):
    return sum(flattenlen(i) if isinstance(i, list) else 1 for i in a)

这总结了列表的递归调用的结果,其余的单个1值,所有这些都在一个生成器表达式循环中。

对于非递归版本,请使用堆栈:

def flattenlen(a):
    total = 0
    stack = [a]
    while stack:
        lst = stack.pop()
        for i in lst:
            if isinstance(i, list):
                stack.append(i)
            else:
                total += 1
    return total

要获得更完整的解决方案,请使用collections.Iterablebasestring来测试任何非字符串(unicodestr)的可迭代对象:

from collections import Iterable

_typetest = lambda t: isinstance(t, Iterable) and not isinstance(t, basestring)

def flattenlen(a):
    return sum(flattenlen(i) if _typetest(i) else 1 for i in a)

演示:

>>> from collections import Iterable
>>> _typetest = lambda t: isinstance(t, Iterable) and not isinstance(t, basestring)
>>> def flattenlen(a):
...     return sum(flattenlen(i) if _typetest(i) else 1 for i in a)
... 
>>> flattenlen([[[[1, 2], [3, 4]], 5], [6, 7]])
7
>>> flattenlen([([[1, 2], [3, 4]], 5), {6, 7, 'foobar'}])
8