2009-11-25 9 views
19

He escrito un programa simple de pitónpitón: Índice de la Lista error fuera de

l=[1,2,3,0,0,1] 
for i in range(0,len(l)): 
     if l[i]==0: 
      l.pop(i) 

Esto me da error 'índice de la lista fuera de rango' en la línea if l[i]==0:

Después de la depuración que pudiera darse cuenta de que i se está incrementando y la lista se está reduciendo.
Sin embargo, tengo la condición de terminación de bucle i < len(l). Entonces, ¿por qué estoy obteniendo tal error?

+1

"Tengo la condición de terminación del ciclo i

+1

@ S. Lott, estoy en el rango (0, len()) significa 'iré hasta len (l) -1' – atv

+3

Otro consejo de Python: podrías haber escrito 'range (len (l))', como 0 es el valor de inicio predeterminado. – abyx

Respuesta

39

Está reduciendo la longitud de su lista l mientras la itera, por lo que al acercarse al final de sus índices en la declaración de rango, algunos de esos índices ya no son válidos.

Se ve como lo que usted quiere hacer es:

l = [x for x in l if x != 0] 

que devolverá una copia de l sin que ninguno de los elementos que eran cero (operación se llama list comprehension, por cierto) . Incluso podría acortar esa última parte a solo if x, ya que los números distintos de cero se evalúan a True.

No hay tal cosa como una condición de terminación del bucle de i < len(l), en la forma en que has escrito el código, porque es len(l) pre calculada antes del bucle, no re-evaluado en cada iteración. Usted podría escribirlo de una manera tal, sin embargo:

i = 0 
while i < len(l): 
    if l[i] == 0: 
     l.pop(i) 
    else: 
     i += 1 
14

La expresión len(l) se evalúa sólo una vez, en el momento en que se evalúa la range() incorporado. El objeto de rango construido en ese momento no cambia; no puede saber nada sobre el objeto l.

P.S. l es un nombre pésimo para un valor! Parece el número 1 o la letra mayúscula I.

5

Está cambiando el tamaño de la lista mientras la repite, lo que probablemente no es lo que quiere y es la causa de su error.

Editar: Como otros han respondido y comentado, las listas de comprensión son mejores como una primera opción y especialmente en respuesta a esta pregunta. Ofrecí esto como una alternativa por esa razón, y aunque no es la mejor respuesta, todavía resuelve el problema.

Por lo tanto, en esa nota, también puede usar filter, que le permite llamar a una función para evaluar los elementos de la lista que no desea.

Ejemplo:

>>> l = [1,2,3,0,0,1] 
>>> filter(lambda x: x > 0, l) 
[1, 2, 3] 

vivir y aprender. Lo simple es mejor, excepto cuando necesitas que las cosas sean complejas.

+3

Ni siquiera necesita la lambda, ya que 0 evalúa a Falso. 'filter (None, l)' –

+1

De hecho, su condición lambda es incorrecta. Pero +1 para 'filtro'. – int3

+0

@Steve Losh - Esto es lo que me encanta de SO ... ¡Aprendiendo pequeños trucos simples para ahorrarme golpes de teclado a largo plazo! ¡Gracias! – jathanism

0

Estoy usando Python 3.3.5. La solución anterior de usar while loop no funcionó para mí. Incluso si puse print (i) después de len(l) me dio un error. Ejecuté el mismo código en la línea de comandos (shell) [ventana que aparece cuando ejecutamos una función] se ejecuta sin error.Lo que hice fue calculado len (l) fuera de la función en el programa principal y pasé la longitud como parámetro. Funcionó. Python es raro a veces.

0

El problema fue que intentó modificar la lista a la que hacía referencia dentro del ciclo que usaba la lista len(). Cuando elimina el elemento de la lista, se calcula el nuevo len() en el siguiente ciclo.

Por ejemplo, después de la primera ejecución, cuando eliminó (i) usando l.pop(i), eso sucedió con éxito pero en el siguiente ciclo la longitud de la lista ha cambiado, por lo que se han cambiado todos los números de índice. Hasta cierto punto, el ciclo intenta pasar por encima de una lista cortada que arroja el error.

Hacer esto fuera del bucle funciona, sin embargo, sería mejor construir y nueva lista declarando primero y lista vacía antes del bucle, y luego dentro del bucle anexar todo lo que desea mantener a la nueva lista.

Para aquellos de ustedes que pueden haber llegado al mismo problema.

3

Lo que Mark Rushakoff dice es verdadero, pero si repite la acción en la dirección opuesta, también es posible eliminar elementos de la lista en for-loop. Por ejemplo,

x = [1,2,3,0,0,1] 
for i in range(len(x)-1, -1, -1): 
    if x[i] == 0: 
     x.pop(i) 

Es como un edificio alto que cae de arriba a abajo: incluso si se encuentra en medio de un colapso, todavía se puede "entrar" en ella y visitar los pisos todavía-a-ser colapsadas.

0

La comprensión de la lista lo llevará a una solución.

Pero la forma correcta de copiar un objeto en python es usando python module copy - Operaciones de copia poco profunda y profunda.

l=[1,2,3,0,0,1] 
for i in range(0,len(l)): 
    if l[i]==0: 
     l.pop(i) 

Si en lugar de esto,

import copy 
l=[1,2,3,0,0,1] 
duplicate_l = copy.copy(l) 
for i in range(0,len(l)): 
    if l[i]==0: 
     m.remove(i) 
l = m 

Entonces, su propio código hubiera funcionado. Pero para la optimización, la comprensión de la lista es una buena solución.

Cuestiones relacionadas