如何获取我任意嵌套列表中的元素总数?

16

我有一个列表赋值给变量my_list。其值为[[1,2,3],[3,5,[2,3]], [[3,2],[5,[4]]]]。我需要找到my_list的长度,但是len(my_list)只返回3。我希望它返回11。是否有任何Python函数可以返回my_list嵌套列表的完整长度。

示例:

Input
[[1,2,3],[3,5,[2,3]], [[3,2],[5,[4]]]]

Output
11

我希望这个功能不仅可以适用于数字,也可以适用于字符串。


1
你希望这个程序能够处理可能包含字符串的嵌套列表,还是列表只包含数字? - PM 2Ring
3
那么您的问题有点误导性,“找到所有嵌套列表的长度?” - thefourtheye
2
这是一个很好的函数,可以将任意嵌套的列表展开:https://dev59.com/THI95IYBdhLWcg3wyBCc#2158532。使用它来展开您的嵌套列表,然后您只需要获取展开列表的 len() 即可。 - PM 2Ring
@michaelpri 请查看我的更新答案。如果那是你需要的,请告诉我。 - Jobs
1
通常情况下,您不知道生成器将产生多少项,直到运行它,并且有些生成器永远不会停止产生项。如果您有一个已知具有有限大小的生成器,则可以从中生成一个列表,然后在该列表上调用len()。例如,len(list(flatten(deep_nested_list))) - PM 2Ring
显示剩余5条评论
7个回答

19

该函数计算列表的长度,将除列表以外的任何对象视为长度1,并在列表项上进行递归以查找平坦长度,在解释器最大堆栈深度范围内可处理任意嵌套程度。

def recursive_len(item):
    if type(item) == list:
        return sum(recursive_len(subitem) for subitem in item)
    else:
        return 1

注意:根据使用情况,最好检查该项是否可迭代,而不是检查它是否具有类型list,以正确判断元组的大小等。但是,检查对象是否可迭代会导致在字符串中计算每个字符而不是给出字符串长度1的副作用,这可能是不希望看到的。


你应该编辑那个 if type(item) == list or type(item) == tuple or type(item)==dict 等等。 - user4414248
5
如果item是可迭代对象且不是字符串类型,则返回True。 - Padraic Cunningham
1
你也可以将一个元组传递给isinstance,如if isinstance(item, (list,tuple)) - Padraic Cunningham

6

作为替代方案,您可以使用flattenlen

from compiler.ast import flatten

my_list = [[1,2,3],[3,5,[2,3]], [[3,2],[5,[4]]]]

len(flatten(my_list))
11

PS. 感谢 @thefourtheye 的指出,请注意:

自2.6版本起已弃用:编译器包在Python 3中已被删除。

可以在此处找到替代方案:Python 3替代已弃用的编译器.ast平坦函数


2
compiler.ast.flatten 已经很久以前就被弃用了。 - thefourtheye

6

这是一个 hack 方法,可能有人已经发布过了。将列表转换为字符串(让 __str__ 操作完成重活和递归),然后计算逗号的数量并加1。

>>> my_list = [[1,2,3],[3,5,[2,3]], [[3,2],[5,[4]]]]
>>> str(my_list).count(",")+1
11

(适用于整数和浮点数,但对字符串无效,因为它们可以包含逗号)

编辑:这种方法不能处理空列表:我们必须删除[]元素:

>>> my_list = [[1,2,3],[3,5,[2,3]], [[3,2],[5,[4],[]]]]  # added empty list at the end
>>> s = str(my_list)
>>> s.count(",")-s.count("[]")+1   # still 11

1
当列表中可能包含,时,对于字符串列表无效。 - Harshal Parekh
1
自2017年10月以来,我的答案中:当涉及到字符串时,__当然会失败,因为它们可能包含逗号__。 - Jean-François Fabre

2

这是一种备选方案,可能不太高效,因为它填充一个新的扁平列表,并在最后返回:

def flatten_list(ls, flattened_list=[]):
    for elem in ls:
        if not isinstance(elem, list): 
            flattened_list.append(elem)
        else:
            flatten_list(elem, flattened_list)
    return flattened_list

flatten_list 直观地将列表展开,然后您可以使用 len() 函数计算新返回的展平列表的长度:

len(flatten_list(my_list))

2
您实际上是在寻找一种计算树中叶子节点数量的方法。
 def is_leaf(tree):
        return type(tree) != list

def count_leaves(tree):
    if is_leaf(tree):
        return 1
    else:
        branch_counts = [count_leaves(b) for b in tree]
        return sum(branch_counts)

count_leaves函数通过递归计算分支的branch_counts,然后将这些结果相加来计算树中的叶子数。基本情况是当树是一个叶子时,即只有1个叶子的树。叶子的数量与树的长度不同,树的长度是其分支数。


0
这是我的实现:
def nestedList(check):
    returnValue = 0
    for i in xrange(0, len(check)):
        if(isinstance(check[i], list)):
            returnValue += nestedList(check[i])
        else:
            returnValue += 1
    return returnValue

0

这是我最好的尝试,利用递归,仅使用标准库和视觉。 我尽量不使用自定义库。

def listlength(mylist, k=0, indent=''):
    for l1 in mylist:
        if isinstance(l1, list):
            k = listlength(l1, k, indent+'  ')
        else:
            print(indent+str(l1))
            k+=1
    return k

a = [[1,2,3],[3,5,[2,3]], [[3,2],[5,[4]]]]
listlength(a)
# 11

而且为了保险起见

a = []
x = listlength(a)
print('length={}'.format(x))
# length=0



a = [1,2,3]
x = listlength(a)
print('length={}'.format(x))
#1
#2
#3
#length=3


a = [[1,2,3]]
x = listlength(a)
print('length={}'.format(x))
#  1
#  2
#  3
#length=3


a = [[1,2,3],[1,2,3]]
x = listlength(a)
print('length={}'.format(x))
#  1
#  2
#  3
#  1
#  2
#  3
#length=6

a = [1,2,3, [1,2,3],[1,2,3]]
x = listlength(a)
print('length={}'.format(x))
#1
#2
#3
#  1
#  2
#  3
#  1
#  2
#  3
#length=9


a = [1,2,3, [1,2,3,[1,2,3]]]
x = listlength(a)
print('length={}'.format(x))
#1
#2
#3
#  1
#  2
#  3
#    1
#    2
#    3
#length=9


a = [ [1,2,3], [1,[1,2],3] ]
x = listlength(a)
print('length={}'.format(x))
#  1
#  2
#  3
#  1
#    1
#    2
#  3
#length=7

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接