OK、溶液を測定しました。逆のソリューションはほぼ同じです。forwardwhile
ループは約 4 倍遅くなります。 しかし! Patrik のダーティソリューションは、100,000 個のランダムな整数のリストに対して約 80 倍高速です[Patrik2 のバグが修正されました] :
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
それで、私はより長いリストで試しました。2倍の長さだけを使用すると、大きな違いが生じます(私の古いコンピューターでは)。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
【ニンジャゲッコのコメントを受けて追記】
修正された Patrik2 解は、2 段階の Patrick 解よりも約 2 倍高速です。
要素の削除頻度がそれほど高くないことをシミュレートするために、テストのようなものif 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/04/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