Как я могу получить общее количество элементов в моем произвольно вложенном списке списков?

У меня есть список, назначенный переменной my_list. Значение 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

Я хотел бы, чтобы это работало не только для чисел, но и для строк.


person michaelpri    schedule 04.01.2015    source источник
comment
Это должно быть правилом. Сколько «вложенных» мы говорим?   -  person    schedule 04.01.2015
comment
Так это только ваш список? Нельзя изменить с помощью других вложенных списков?   -  person    schedule 04.01.2015
comment
Вы хотите, чтобы это работало с вложенными списками, которые могут содержать строки, или списки содержат только числа?   -  person PM 2Ring    schedule 04.01.2015
comment
Можете ли вы перечислить 11 списков, найденных во входных данных?   -  person thefourtheye    schedule 04.01.2015
comment
@michaelpri Тогда ваш вопрос немного вводит в заблуждение, найдите длину всех вложенных списков?   -  person thefourtheye    schedule 04.01.2015
comment
Вот хорошая функция для выравнивания произвольных вложенных списков: stackoverflow.com/a/2158532/4014959 . Используйте это, чтобы сгладить свой вложенный список, тогда вам просто нужно получить len() сглаженного списка.   -  person PM 2Ring    schedule 04.01.2015
comment
возможный дубликат Flatten (нерегулярный) список списков в Python   -  person    schedule 04.01.2015
comment
@michaelpri, пожалуйста, посмотрите мой обновленный ответ. Дайте мне знать, если это то, что вам нужно.   -  person Jobs    schedule 04.01.2015
comment
@PM2Ring Я получаю TypeError: object of type 'generator' has no len(), когда печатаю(len(flatten(deep_nested_list)))   -  person ruslaniv    schedule 05.09.2020
comment
@RusI В общем, вы не знаете, сколько предметов произведет генератор, пока не запустите его, а некоторые генераторы никогда не прекращают производить предметы. Если у вас есть генератор, который, как вы знаете, имеет конечный размер, вы можете создать из него список, а затем вызвать len() в этом списке. Например, len(list(flatten(deep_nested_list)))   -  person PM 2Ring    schedule 06.09.2020


Ответы (7)


Эта функция подсчитывает длину списка, считая любой объект, кроме списка, равным 1, и выполняет рекурсию по элементам списка, чтобы найти сглаженную длину, и будет работать с любой степенью вложенности вплоть до максимальной глубины стека интерпретатора.

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

Примечание: в зависимости от того, как это будет использоваться, может быть лучше проверить, является ли элемент итерируемым, а не проверять, имеет ли он тип list, чтобы правильно оценить размер кортежей и т. д. Однако проверка того, является ли объект iterable будет иметь побочный эффект подсчета каждого символа в строке, а не присвоение длины строки 1, что может быть нежелательно.

person stonesam92    schedule 04.01.2015
comment
Вы должны отредактировать это if type(item) == list or type(item) == tuple or type(item)==dict и т. д. - person ; 04.01.2015
comment
Вы также можете передать кортеж в issinstance if isinstance(item, (list,tuple)) - person Padraic Cunningham; 04.01.2015

взломать решение, кто-то должен был опубликовать его. Преобразуйте список в строку (оставьте тяжелый подъем/рекурсию оператору __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
person Jean-François Fabre    schedule 11.10.2017
comment
Не работает для списка строк, когда в списке может быть , - person Harshal Parekh; 06.11.2019
comment
в моем ответе с октября 2017 г .: конечно, не работает со строками, потому что они могут содержать запятые - person Jean-François Fabre; 06.11.2019

В качестве альтернативы вы можете использовать flatten с len:

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 функция сглаживания

person Anzel    schedule 04.01.2015
comment
compiler.ast.flatten давно устарела. - person thefourtheye; 04.01.2015

По сути, вы ищете способ вычислить количество листьев в дереве.

 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 листом. Количество листьев отличается от длины дерева, то есть количества его ветвей.

person Jobs    schedule 04.01.2015

Это альтернативное решение, которое может быть не таким эффективным, поскольку оно заполняет новый плоский список, который возвращается в конце:

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))
person nbro    schedule 04.01.2015

Вот моя реализация:

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
person ProgrammingIsAwsome    schedule 04.01.2015

Это моя лучшая попытка, использующая рекурсию и использующая только стандартную библиотеку и визуализацию. Я стараюсь не использовать пользовательские библиотеки

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
person nagordon    schedule 09.04.2020