Bien, he medido la solución. Las soluciones invertidas son casi lo mismo. El ciclo while
hacia adelante es aproximadamente 4 veces más lento. PERO! solución del Patrik sucia es aproximadamente 80 veces más rápido para la lista de 100.000 enteros aleatorios [bug en Patrik2 corregido]:
import timeit
import random
def solution_ninjagecko1(lst):
for i in xrange(len(lst)-1, -1, -1):
if lst[i] % 2 != 0: # simulation of the choice
del lst[i]
return lst
def solution_jdi(lst):
L = len(lst) - 1
for i, v in enumerate(reversed(lst)):
if v % 2 != 0:
lst.pop(L-i) # L-1 is the forward index
return lst
def solution_Patrik(lst):
for i, v in enumerate(lst):
if v % 2 != 0: # simulation of the choice
lst[i] = None
return [v for v in lst if v is not None]
def solution_Patrik2(lst):
##buggy lst = [v for v in lst if v % 2 != 0]
##buggy return [v for v in lst if v is not None]
# ... corrected to
return [v for v in lst if v % 2 != 0]
def solution_pepr(lst):
i = 0 # indexing the processed item
n = 0 # enumerating the original position
while i < len(lst):
if lst[i] % 2 != 0: # simulation of the choice
del lst[i] # i unchanged if item deleted
else:
i += 1 # i moved to the next
n += 1
return lst
def solution_pepr_reversed(lst):
i = len(lst) - 1 # indexing the processed item backwards
while i > 0:
if lst[i] % 2 != 0: # simulation of the choice
del lst[i] # i unchanged if item deleted
i -= 1 # i moved to the previous
return lst
def solution_steveha(lst):
def should_keep(x):
return x % 2 == 0
return filter(should_keep, lst)
orig_lst = range(30)
print 'range() generated list of the length', len(orig_lst)
print orig_lst[:20] + ['...'] # to have some fun :)
lst = orig_lst[:] # copy of the list
print solution_ninjagecko1(lst)
lst = orig_lst[:] # copy of the list
print solution_jdi(lst)
lst = orig_lst[:] # copy of the list
print solution_Patrik(lst)
lst = orig_lst[:] # copy of the list
print solution_pepr(lst)
orig_lst = [random.randint(1, 1000000) for n in xrange(100000)]
print '\nrandom list of the length', len(orig_lst)
print orig_lst[:20] + ['...'] # to have some fun :)
lst = orig_lst[:] # copy of the list
t = timeit.timeit('solution_ninjagecko1(lst)',
'from __main__ import solution_ninjagecko1, lst',
number=1)
print 'solution_ninjagecko1: ', t
lst = orig_lst[:] # copy of the list
t = timeit.timeit('solution_jdi(lst)',
'from __main__ import solution_jdi, lst',
number=1)
print 'solution_jdi: ', t
lst = orig_lst[:] # copy of the list
t = timeit.timeit('solution_Patrik(lst)',
'from __main__ import solution_Patrik, lst',
number=1)
print 'solution_Patrik: ', t
lst = orig_lst[:] # copy of the list
t = timeit.timeit('solution_Patrik2(lst)',
'from __main__ import solution_Patrik2, lst',
number=1)
print 'solution_Patrik2: ', t
lst = orig_lst[:] # copy of the list
t = timeit.timeit('solution_pepr_reversed(lst)',
'from __main__ import solution_pepr_reversed, lst',
number=1)
print 'solution_pepr_reversed: ', t
lst = orig_lst[:] # copy of the list
t = timeit.timeit('solution_pepr(lst)',
'from __main__ import solution_pepr, lst',
number=1)
print 'solution_pepr: ', t
lst = orig_lst[:] # copy of the list
t = timeit.timeit('solution_steveha(lst)',
'from __main__ import solution_steveha, lst',
number=1)
print 'solution_steveha: ', t
Imprime en mi consola:
c:\tmp\_Python\Patrick\so10305762>python a.py
range() generated list of the length 30
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, '...']
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28]
random list of the length 100000
[915411, 954538, 794388, 847204, 846603, 454132, 866165, 640004, 930488, 609138,
333405, 986073, 318301, 728151, 996047, 117633, 455353, 581737, 55350, 485030,
'...']
solution_ninjagecko1: 2.41921752625
solution_jdi: 2.45477176569
solution_Patrik: 0.0468565138865
solution_Patrik2: 0.024270403082
solution_pepr_reversed: 2.43338888043
solution_pepr: 9.11879694207
Por lo tanto, Lo intenté con una lista más larga. Usar solo el doble de tiempo hace una gran diferencia (en mi computadora vieja). La solución dirty de Patrik se comporta muy bien. Es aproximadamente 200 veces más rápido que las soluciones invertidas:
random list of the length 200000
[384592, 170167, 598270, 832363, 123557, 81804, 319315, 445945, 178732, 726600,
516835, 392267, 552608, 40807, 349215, 208111, 880032, 520614, 384119, 350090,
'...']
solution_ninjagecko1: 17.362140719
solution_jdi: 17.86837545
solution_Patrik: 0.0957998851809
solution_Patrik2: 0.0500024444448
solution_pepr_reversed: 17.5078452708
solution_pepr: 52.175648581
[Alta después de los comentarios de ninjagecko]
La solución Patrik2 corregido es aproximadamente dos veces más rápido que la solución de Patrick 2 etapas.
Para simular la eliminación no tan frecuente de los elementos, la prueba como if v % 2 != 0:
se cambió a if v % 100 == 0:
. Entonces aproximadamente el 1% de los artículos se deben eliminar. Es obvio que lleva menos tiempo. Por 500.000 enteros aleatorios en la lista, los resultados son los siguientes:
random list of the length 500000
[403512, 138135, 552313, 427971, 42358, 500926, 686944, 304889, 916659, 112636,
791585, 461948, 82622, 522768, 485408, 774048, 447505, 830220, 791421, 580706,
'...']
solution_ninjagecko1: 6.79284210703
solution_jdi: 6.84066913532
solution_Patrik: 0.241242951269
solution_Patrik2: 0.162481823807
solution_pepr_reversed: 6.92106007886
solution_pepr: 7.12900522273
solución de Patrick es stil alrededor de 30 veces más rápido.
[Agregado 2012/04/25]
Otra solución que funciona en el lugar, que los bucles hacia adelante, y que es tan rápido como solución de Patrick. No mueve toda la cola cuando se elimina el elemento. En cambio, mueve los elementos deseados a su posición final y luego corta la cola no utilizada de la lista.
def solution_pepr2(lst):
i = 0
for v in lst:
lst[i] = v # moving the element (sometimes unneccessary)
if v % 100 != 0: # simulation of the choice
i += 1 # here will be the next one
lst[i:] = [] # cutting the tail of the length of the skipped
return lst
# The following one only adds the enumerate to simulate the situation when
# it is needed -- i.e. slightly slower but with the same complexity.
def solution_pepr2enum(lst):
i = 0
for n, v in enumerate(lst):
lst[i] = v # moving the element (sometimes unneccessary)
if v % 100 != 0: # simulation of the choice
i += 1 # here will be the next one
lst[i:] = [] # cutting the tail of the length of the skipped
return lst
En comparación con las soluciones anteriores para v % 100 != 0
:
random list of the length 500000
[533094, 600755, 58260, 295962, 347612, 851487, 523927, 665648, 537403, 238660,
781030, 940052, 878919, 565870, 717745, 408465, 410781, 560173, 51010, 730322,
'...']
solution_ninjagecko1: 1.38956896051
solution_jdi: 1.42314502685
solution_Patrik: 0.135545530079
solution_Patrik2: 0.0926935780151
solution_pepr_reversed: 1.43573239178
solution_steveha: 0.122824246805
solution_pepr2: 0.0938177241656
solution_pepr2enum: 0.11096263294
Quédese con su solución * sucia *. Es claramente el más rápido y el menos problemático. – pepr