Mueve todos los ceros al principio de una lista en Python

Tengo una lista como la siguiente:

a = [4, 5, 0, 0, 6, 7, 0, 1, 0, 5] 

y quiero empujar todos los ceros al principio de esa lista. El resultado debe ser como abajo.

 a = [0, 0, 0, 0, 4, 5, 6, 7, 1, 5] 

¿Cómo hacerlo en Python 2?

Podrías ordenar la lista:

 a.sort(key=lambda v: v != 0) 

La función key le dice a Python que ordene los valores, ya sea o no, que son 0 . False se clasifica antes de True , y los valores se ordenan según su posición relativa original.

Para 0 , se devuelve False , ordenando todos esos valores primero. Por lo demás, se devuelve True , dejando ordenado para ponerlos en último lugar, pero sin tocar sus posiciones relativas.

Manifestación:

 >>> a = [4, 5, 0, 0, 6, 7, 0, 1, 0, 5] >>> a.sort(key=lambda v: v != 0) >>> a [0, 0, 0, 0, 4, 5, 6, 7, 1, 5] 

Esto se puede hacer sin clasificar.

Soluciones

Inicialización:

 In [8]: a = [4, 5, 0, 0, 6, 7, 0, 1, 0, 5] In [9]: from itertools import compress, repeat, chain 

list.count y itertools.compress

 In [10]: x = [0] * a.count(0); x.extend(compress(a, a)) In [11]: x Out[11]: [0, 0, 0, 0, 4, 5, 6, 7, 1, 5] 

Igual que antes, pero sin list.count

 In [12]: c = list(compress(a, a)); [0] * (len(a) - len(c)) + c Out[12]: [0, 0, 0, 0, 4, 5, 6, 7, 1, 5] 

list.count , itertools.compress , itertools.repeat , itertools.chain

 In [13]: list(chain(repeat(0, a.count(0)), compress(a, a))) Out[13]: [0, 0, 0, 0, 4, 5, 6, 7, 1, 5] 

Igual que el anterior, pero sin list.count

 In [14]: c = list(compress(a, a)); list(chain(repeat(0, len(a) - len(c)), c)) Out[14]: [0, 0, 0, 0, 4, 5, 6, 7, 1, 5] 

Puntos de referencia

Para pequeñas listas:

 In [21]: %timeit x = [0] * a.count(0); x.extend(compress(a, a)) 1000000 loops, best of 3: 583 ns per loop In [22]: %timeit c = list(compress(a, a)); [0] * (len(a) - len(c)) + c 1000000 loops, best of 3: 661 ns per loop In [23]: %timeit list(chain(repeat(0, a.count(0)), compress(a, a))) 1000000 loops, best of 3: 762 ns per loop In [24]: %timeit c = list(compress(a, a)); list(chain(repeat(0, len(a) - len(c)), c)) 1000000 loops, best of 3: 900 ns per loop 

Para listas grandes:

 In [28]: a *= 10000000 In [29]: %timeit x = [0] * a.count(0); x.extend(compress(a, a)) 1 loops, best of 3: 1.43 s per loop In [30]: %timeit c = list(compress(a, a)); [0] * (len(a) - len(c)) + c 1 loops, best of 3: 1.37 s per loop In [31]: %timeit list(chain(repeat(0, a.count(0)), compress(a, a))) 1 loops, best of 3: 1.79 s per loop In [32]: %timeit c = list(compress(a, a)); list(chain(repeat(0, len(a) - len(c)), c)) 1 loops, best of 3: 1.47 s per loop 

Como puede ver, en algunos casos las itertools basadas en itertools tienden a ser más lentas, debido al gran número de llamadas a funciones.

Aquí hay algunos mejores tiempos, con dos nuevos métodos:

 SETUP=" from itertools import compress, repeat, chain a = [4, 5, 0, 0, 6, 7, 0, 1, 0, 5] " 

Primero la clasificación:

 python -m timeit -s "$SETUP" "a.sort(key=bool)" # 1000000 loops, best of 3: 1.51 usec per loop 

Luego los métodos de frostnational:

 python -m timeit -s "$SETUP" "list(chain(repeat(0, a.count(0)), compress(a, a)))" # 1000000 loops, best of 3: 1.16 usec per loop python -m timeit -s "$SETUP" "cs = list(compress(a, a)); list(chain(repeat(0, len(a)-len(cs)), cs))" # 1000000 loops, best of 3: 1.37 usec per loop 

A continuación, los métodos más directamente trabajando desde listas:

 python -m timeit -s "$SETUP" "[0] * a.count(0) + list(filter(bool, a))" # 1000000 loops, best of 3: 1.04 usec per loop python -m timeit -s "$SETUP" "nonzero = list(filter(bool, a)); [0] * (len(a)-len(nonzero)) + nonzero" # 1000000 loops, best of 3: 0.87 usec per loop 

Y de nuevo con entrada de mayor tamaño:

 SETUP=" from itertools import compress, repeat, chain a = [4, 5, 0, 0, 6, 7, 0, 1, 0, 5] * 1000 " 

Clasificación:

 python -m timeit -s "$SETUP" "a.sort(key=bool)" # 1000 loops, best of 3: 1.08 msec per loop 

frostnacionales de

 python -m timeit -s "$SETUP" "list(chain(repeat(0, a.count(0)), compress(a, a)))" # 1000 loops, best of 3: 333 usec per loop python -m timeit -s "$SETUP" "cs = list(compress(a, a)); list(chain(repeat(0, len(a)-len(cs)), cs))" # 1000 loops, best of 3: 206 usec per loop 

Nuevo:

 python -m timeit -s "$SETUP" "[0] * a.count(0) + list(filter(bool, a))" # 1000 loops, best of 3: 295 usec per loop python -m timeit -s "$SETUP" "nonzero = list(filter(bool, a)); [0] * (len(a)-len(nonzero)) + nonzero" # 10000 loops, best of 3: 143 usec per loop 

Dicho esto, a pesar de ser relativamente lento, la decisión de Martijn Pieters de usar la clasificación es en realidad bastante competitiva para listas de tamaño razonable y la optimización prematura es la raíz de todo mal.


FWIW, aquí hay algunos tiempos para listas muy largas:

 SETUP=" from itertools import compress, repeat, chain a = [4, 5, 0, 0, 6, 7, 0, 1, 0, 5] * 1000000 " python -m timeit -s "$SETUP" "a.sort(key=bool)" # 10 loops, best of 3: 1.21 sec per loop python -m timeit -s "$SETUP" "list(chain(repeat(0, a.count(0)), compress(a, a)))" # 10 loops, best of 3: 347 msec per loop python -m timeit -s "$SETUP" "cs = list(compress(a, a)); list(chain(repeat(0, len(a)-len(cs)), cs))" # 10 loops, best of 3: 226 msec per loop python -m timeit -s "$SETUP" "[0] * a.count(0) + list(filter(bool, a))" # 10 loops, best of 3: 310 msec per loop python -m timeit -s "$SETUP" "nonzero = list(filter(bool, a)); [0] * (len(a)-len(nonzero)) + nonzero" # 10 loops, best of 3: 153 msec per loop 

Intente este proceso simple: –

 from collections import deque a = [4, 5, 0, 0, 6, 7, 0, 1, 0, 5] b = deque([x for x in a if x!=0]) for i in a: if i==0: b.appendleft(0) print list(b) #output -> [0, 0, 0, 0, 4, 5, 6, 7, 1, 5]