好的,我已经测量了解决方案。颠倒的解决方案大致相同。前向while
循环慢了大约 4 倍。 但!对于 100,000 个随机整数列表[Patrik2 中的错误已更正] ,Patrik 的脏解决方案大约快 80 倍:
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
它打印在我的控制台上:
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
所以,我尝试了更长的列表。只使用两倍的时间会产生很大的不同(在我的旧电脑上)。Patrik 的肮脏解决方案表现得非常好。它比反向解决方案快约 200 倍:
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
[在 ninjagecko 评论后添加]
修正后的 Patrik2 解决方案比 2 阶段 Patrick 解决方案快大约两倍。
为了模拟不那么频繁地删除元素,测试 likeif v % 2 != 0:
已更改为if v % 100 == 0:
. 然后应该删除大约 1% 的项目。很明显,它需要更少的时间。对于列表中的 500,000 个随机整数,结果如下:
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
Patrick 的解决方案仍然快 30 倍左右。
[添加于 2012 年 4 月 25 日]
另一种就地工作的解决方案,向前循环,与帕特里克的解决方案一样快。删除元素时,它不会移动所有尾部。相反,它将想要的元素移动到它们的最终位置,然后切断列表中未使用的尾部。
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
与上述解决方案相比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