resultado extraño al eliminar un elemento de una lista

Tengo este pedazo de código:

numbers = range(1, 50) for i in numbers: if i < 20: numbers.remove(i) print(numbers) 

pero el resultado que estoy obteniendo es:

[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 , 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]

Por supuesto, estoy esperando que los números por debajo de 20 no aparezcan en los resultados, supongo que estoy haciendo algo mal con la eliminación.

Estás modificando la lista mientras iteras sobre ella. Eso significa que la primera vez a través del bucle, i == 1 , por lo que 1 se elimina de la lista. Luego, el bucle for va al segundo elemento de la lista, que no es 2, sino 3! Luego se elimina de la lista, y luego el bucle for pasa al tercer elemento de la lista, que ahora es 5. Y así sucesivamente. Tal vez sea más fácil de visualizar así, con una ^ apuntando al valor de i :

 [1, 2, 3, 4, 5, 6...] ^ 

Ese es el estado de la lista inicialmente; luego se elimina 1 y el bucle va al segundo elemento de la lista:

 [2, 3, 4, 5, 6...] ^ [2, 4, 5, 6...] ^ 

Y así.

No hay una buena manera de alterar la longitud de una lista mientras se itera sobre ella. Lo mejor que puedes hacer es algo como esto:

 numbers = [n for n in numbers if n >= 20] 

o esto, para una modificación in situ (la cosa en parens es una expresión generadora, que se convierte implícitamente en una tupla antes de la asignación de segmentos):

 numbers[:] = (n for in in numbers if n >= 20) 

Si desea realizar una operación en n antes de eliminarlo, un truco que podría intentar es este:

 for i, n in enumerate(numbers): if n < 20 : print "do something" numbers[i] = None numbers = [n for n in numbers if n is not None] 

¡La respuesta de @ senderle es el camino a seguir!

Dicho esto para ilustrar aún más un poco más tu problema, si lo piensas, siempre querrás eliminar el índice 0 veinte veces:

 [1,2,3,4,5............50] ^ [2,3,4,5............50] ^ [3,4,5............50] ^ 

Así que realmente podrías ir con algo como esto:

 aList = range(50) i = 0 while i < 20: aList.pop(0) i += 1 print aList #[21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49] 

Espero que ayude.


Los de abajo no son malas prácticas AFAIK.

EDITAR (algunos más):

 lis = range(50) lis = lis[20:] 

Hará el trabajo también.

EDIT2 (estoy aburrido):

 functional = filter(lambda x: x> 20, range(50)) 

Eliminar elementos de una lista es simple: comience al final de la lista:

 li = range(1,15) print li,'\n' for i in xrange(len(li)-1,-1,-1): if li[i] < 6: del li[i] print li 

resultado

 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] [6, 7, 8, 9, 10, 11, 12, 13, 14] 

Realmente me gusta la respuesta proporcionada por @senderle. Lo único que quiero agregar (habría comentado, pero no puedo obtener el formato de código correcto) es que también puede salirse con el procesamiento lateral para sus listas de comprensión si declara sus funciones con anticipación, como por ejemplo:

 def checkRemoval(item): # some processing here return passed_inspection # Should be True / False. newList = [item for item in oldList if checkRemoval(item)]