Python: Eliminar elemento de lista mientras se itera sobre lista

Estoy iterando sobre una lista de elementos en Python, hago algo al respecto y luego los elimino si cumplen ciertos criterios.

for element in somelist: do_action(element) if check(element): remove_element_from_list 

¿Qué debo usar en lugar de remove_element? He visto preguntas similares, pero note la presencia de la parte do_action que debe ejecutarse para todos los elementos y, por lo tanto, elimina la solución de usar filtros.

Siempre puede iterar sobre una copia de la lista, dejándolo libre de modificar el original:

 for item in list(somelist): ... somelist.remove(item) 

Para cumplir con estos criterios: modificar la lista original in situ, no hay copias de la lista, solo funciona una pasada, una solución tradicional es iterar hacia atrás :

 for i in xrange(len(somelist) - 1, -1, -1): element = somelist[i] do_action(element) if check(element): del somelist[i] 

Bonus: No hace len(somelist) en cada iteración. Funciona en cualquier versión de Python (al menos 1.5.2) … s / xrange / range / para 3.X.

Actualización: si desea iterar hacia delante , es posible, más complicado y más feo:

 i = 0 n = len(somelist) while i < n: element = somelist[i] do_action(element) if check(element): del somelist[i] n = n - 1 else: i = i + 1 

Lista comp:

 results = [x for x in (do_action(element) for element in somelist) if check(element)] 
 for element in somelist: do_action(element) somelist[:] = (x for x in somelist if not check(x)) 

Si realmente necesitas hacerlo en una sola pasada sin copiar la lista

 i=0 while i < len(somelist): element = somelist[i] do_action(element) if check(element): del somelist[i] else: i+=1 

Aún puede usar el filtro, moviendo a una función externa la modificación del elemento (iterando solo una vez)

 def do_the_magic(x): do_action(x) return check(x) # you can get a different filtered list filter(do_the_magic,yourList) # or have it modified in place (as suggested by Steven Rumbalski, see comment) yourList[:] = itertools.ifilter(do_the_magic, yourList) 

Puedes hacer un generador que devuelva todo lo que no se elimina:

 def newlist(somelist): for element in somelist: do_action(element) if not check(element): yield element 

Otra forma de hacerlo es:

 while i 

Entonces, borras los elementos lado a lado mientras revisas

¿Por qué no reescribirlo para ser?

 for element in somelist: do_action(element) if check(element): remove_element_from_list 

Consulta esta pregunta para saber cómo eliminar de la lista, aunque parece que ya has visto que se eliminan elementos de una lista mientras se está iterando.

Otra opción es hacer esto si realmente quieres mantener esto igual.

 newlist = [] for element in somelist: do_action(element) if not check(element): newlst.append(element) 

No exactamente en el lugar, pero alguna idea para hacerlo:

 a = ['a', 'b'] def inplace(a): c = [] while len(a) > 0: e = a.pop(0) if e == 'b': c.append(e) a.extend(c) 

Puede extender la función para llamarle filtro en la condición.