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

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


arrow_upward
19
arrow_downward

Эта функция подсчитывает длину списка, считая любой объект, кроме списка, равным 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

arrow_upward
6
arrow_downward

взломать решение, кто-то должен был опубликовать его. Преобразуйте список в строку (оставьте тяжелый подъем/рекурсию оператору __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

arrow_upward
6
arrow_downward

В качестве альтернативы вы можете использовать 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

arrow_upward
2
arrow_downward

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

 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

arrow_upward
2
arrow_downward

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

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

arrow_upward
0
arrow_downward

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

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

arrow_upward
0
arrow_downward

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

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