Подсчитайте все элементы в списке произвольного вложенного списка без рекурсии

Я только что узнал о рекурсии в Python и завершил присвоения, одним из которых было подсчет всех элементов в списке произвольно вложенных списков. Я искал этот сайт, и все найденные ответы, похоже, используют рекурсивные вызовы. Поскольку было показано, что все, что может быть выражено рекурсивно, может быть выражено итеративно, а итерация предпочтительна в Python, как это будет выполнено без рекурсии или импортированных модулей в Python 2.6 (в качестве учебного упражнения)? (Сам вложенный список будет считаться как элемент, так же как и его содержимое.) Например:

>>> def element_count(p):
...     count = 0
...     for entry in p:
...         count += 1
...         if isinstance(entry, list):            
...             count += element_count(entry)
...     return count
>>> print element_count([1, [], 3]) 
3 
>>> print element_count([1, [1, 2, [3, 4]]])
7
>>> print element_count([[[[[[[[1, 2, 3]]]]]]]])
10

Как это будет написано с помощью итерации?

Ответы

Ответ 1

Вот один из способов сделать это:

def element_count(p):
  q = p[:]
  count = 0
  while q:
    entry = q.pop()
    if isinstance(entry, list):
      q += entry
    count += 1
  return count

print element_count([1, [], 3]) 
print element_count([1, [1, 2, [3, 4]]])
print element_count([[[[[[[[1, 2, 3]]]]]]]])

Код поддерживает очередь вещей, на которые нужно смотреть. Всякий раз, когда цикл встречает суб-список, он добавляет его содержимое в очередь.

Ответ 2

Обычно каждая рекурсивная проблема может быть преобразована в итеративную с помощью стека, в этом случае a list:

def element_count(p):
    elements = list(p)
    count = 0
    while elements:
        entry = elements.pop()
        count += 1
        if isinstance(entry, list):
            elements.extend(entry)
    return count

Ответ 3

Вы можете найти эту версию element_count несколько более мощной, чем другие. Он может обрабатывать все контейнеры, поддерживающие итерацию, и он правильно идентифицирует рекурсивные контейнеры как имеющие бесконечное количество элементов.

>>> def element_count(p):
    stack, pointers, count = [iter(p)], set([id(p)]), 0
    while stack:
        for item in stack.pop():
            try:
                iterator = iter(item)
            except TypeError:
                pass
            else:
                location = id(item)
                if location in pointers:
                    return float('inf')
                stack.append(iterator)
                pointers.add(location)
            count += 1
    return count

>>> element_count([1, [], 3])
3
>>> element_count([1, [1, 2, [3, 4]]])
7
>>> element_count([[[[[[[[1, 2, 3]]]]]]]])
10
>>> p = [1, 2, 3]
>>> element_count(p)
3
>>> p.append({4, 5, 6})
>>> element_count(p)
7
>>> p.append(p)
>>> element_count(p)
inf
>>>