2012-05-14 16 views
14

Acabo de enterarme de la recursión en Python y he completado las asignaciones, una de las cuales era contar todos los elementos dentro de una lista de listas anidadas arbitrariamente. He buscado este sitio y las respuestas encontradas parecen usar llamadas recursivas. Dado que se ha enseñado que todo lo que podría expresarse recursivamente podría expresarse de forma iterativa, y se prefiere la iteración en Python, ¿cómo se lograría esto sin recursión o módulos importados en Python 2.6 (como ejercicio de aprendizaje)? (Una lista anidada en sí sería considerado como un elemento, al igual que su contenido.) Por ejemplo:Cuenta todos los elementos en la lista de lista anidada arbitraria sin recursión

>>> 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 

¿Cómo se escriba esto usando iteración?

+14

Iteración es preferible para cosas como bucles simples. Para problemas inherentemente recursivos como este, la recursión es mejor. – interjay

+0

Esto fue más un ejercicio de aprendizaje que una declaración de principios. Y parece ser más fácil expresar una solución recursivamente. Sin embargo, si la cantidad de llamadas recursivas necesarias se desconoce de antemano, ¿no sería práctico y necesario este ejercicio? –

+1

¿No debería 'element_count ([1, [1, 2, [3, 4]]])' ser 5? ¿Por qué estás contando los objetos de la sublista como elementos? –

Respuesta

17

Aquí es una manera de hacerlo:

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]]]]]]]]) 

El código mantiene una cola de cosas para ser mirado. Cada vez que el bucle encuentra una sublista, agrega su contenido a la cola.

+4

Debido al límite de recursión incorporado de Python, en realidad * es * a menudo una buena idea implementar algoritmos recursivos como iterativos con una pila explícita. Estoy pensando en, por ejemplo, DFS y algoritmos de gráficos similares, que excederán el límite de recursividad para todos menos para los problemas más pequeños. –

+3

Esta función es destructiva. Modificará la lista que se le pasó. –

+2

@NoufalIbrahim: Punto justo. Código actualizado – NPE

10

Por lo general, cada problema recursivo se puede convertir en un proceso iterativo de alguna manera mediante el uso de una pila, en este caso un 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 
+0

es básicamente lo mismo que la versión @aix, pero conserva la lista original – mata

+0

¿Por qué se usaría en vez de en este ejemplo? –

+1

'while elements' en una lista es lo mismo que' while len (elements)> 0', será verdadero siempre que haya algo para 'pop' en ella. a medida que sigamos añadiendo y eliminando de la lista dentro del ciclo, un bucle 'for' no funcionaría aquí. – mata

2

Usted puede encontrar esta versión de element_count a ser algo más poderoso que los otros. Puede manejar todos los contenedores que admiten iteración e identifica correctamente contenedores recursivos que tienen un número infinito de elementos.

>>> 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 
>>> 
+0

¿Esto no plantea un SyntaxError: '{id (p)}'? –

+1

¡Perdón por eso! Python 3.2.3 permite la notación de conjunto literal.El ejemplo anterior se ha corregido para que funcione ahora. –

+0

Esto ciertamente explica más posibilidades de entrada. Interesante, gracias! –

Cuestiones relacionadas