Recorrer y eliminar todos los ceros de una lista

publicado por: Anonymous

Tengo la lista

a = [1,2,0,3,0]

Y necesito eliminar los ceros de modo que la lista para tener esto

a = [1,2,3]

solución

En general, eliminar cosas de una estructura de datos mientras se recorre la estructura es peligroso. Es el equivalente de serrar una rama de un árbol mientras estás sentado en ella 🙂

La estrategia típica es hacer una función que, en lugar de elminar elementos, cree una nueva lista vacía y le vaya añadiendo elementos de la otra, saltándose los que querrías eliminar, para finalmente retornar la nueva lista.

Usando esta idea:

def elimina_ceros(original):
    nueva = []
    for dato in original:
        if dato != 0:
            nueva.append(dato)
    return nueva


a = [1,2,0,3,0]
a = elimina_ceros(a)

Y si haces uso de la sintaxis list comprehension puedes ahorrarte la función anterior y la cosa queda tan simple como:

>>> a = [1,2,0,3,0]
>>> a = [elemento for elemento in a if elemento !=0]
>>> a
[1, 2, 3]

Ten en cuenta que, tanto en el caso de la función como en el dela list comprehension no estamos quitando nada de la lista original, sino creando una nueva. No obstante, al asignar el resultado a la misma variable a, la lista original quedará “sin nombre” y el recolector de basura de python la eliminará de memoria.

Actualización El usuario sugirió en un comentario el utilizar a.remove(0) como parte de un bucle for en que se detectan ceros. Este enfoque no funciona bien como puede verse en el siguiente ejemplo:

a = [1,0,2,0,0,3,4,0]
for i in a:
    if i==0:
        a.remove(0)
    print(a)          # Incluyo este print para ver cosas raras

La salida es:

[1, 0, 2, 0, 0, 3, 4, 0]
[1, 2, 0, 0, 3, 4, 0]
[1, 2, 0, 3, 4, 0]
[1, 2, 0, 3, 4, 0]
[1, 2, 0, 3, 4, 0]
[1, 2, 3, 4, 0]

Y el valor final de a es [1, 2, 3, 4, 0] en el que como vemos no se han eliminado todos los ceros. Observa en concreto las salidas en la tercera, cuarta y quinta iteraciones del bucle. ¡Son iguales!

A esto precisamente me refería cuando decía que no es seguro eliminar elementos mientras se itera por ellos. El for construye un iterador a partir de la lista inicial, si esa lista se cambia dentro del for los resultados son imprevisibles.

Pero esa idea me ha sugerido otra aún más fea 🙂 Se trata de invocar repetidamente a a.remove(0) hasta que no queden más ceros. Pero en este caso sin usar un iterador, sino simplemente “insistiendo” en un bucle infinito, hasta obtener la excepción ValueError que se produce cuando intentemos eliminar un cero y ya no hay más.

El (horrible) código es éste. Lo pongo sólo como curiosidad. No lo intenten en sus casas:

a = [1,0,2,0,0,3,4,0]
while True:
   try:
     a.remove(0)
   except ValueError:
     break
Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *