2016-07-14 115 views
1

我有一個列表lst(與10K項目),查詢詞q,我想找到如果lst任何物品與q結束Efficent搜索。通過列表項

作爲參考定時器I設定爲1,則該語句:

x = q in lst 

我嘗試這些:

# obvious endswith method 
y = [k for k in lst if k.endswith(q)] 
# find method 
z = [k for k in lst if k.find(q, len(k)-len(q))] 
# regex 
v = [k for k in lst if re.search(q + '$', k)] 
# regex without list comprehension 
w = re.search(q + '~', '~'.join(lst) + '~') 

與這些結果(定時針對x定時器):

x: 1 
y: 650 
z: 1209 
v: 7160 
w: 241 

所以我想我可以去正則表達式和加入列表,除非有更好的實現。

在現實世界中,我試圖優化多次執行時的代碼塊,並且我發現該列表理解與.endswith方法是瓶頸。

+0

是否只想找到,如果在'lst'任何物品與'q'結束,或者你需要一個列表以'q'結尾的項目? – Greg

+0

只是爲了找到是否有這樣的項目 - 真/假 – vedar

+0

在正則表達式搜索中的'''.join(lst)'可以在循環外部分配,這給正則表達式搜索3倍提升,在這種類型的搜索中使用循環。 – vedar

回答

1

我不認爲正則表達式是要走的路。即使當我在循環外部指定joined = '~'.join(lst) + '~'時,q+'~' in joined優於re.search(q + '~', joined)(0.00093秒比0.0034秒)。

但是,假設您不會有連接的字符串,不需要它的方法可能會更快。生成器可能很有用,因爲它只會在您需要時生成值(所以只要您在一個項目的末尾發現查詢,就可以停止,而不是檢查列表的其餘部分)。

這是最快的了我:any(k for k in lst if k.endswith(q))

我的代碼:

import timeit 

setup = ''' 

import string 
import random 
import re 

lst = [] 
for i in range(10000): 
    lst.append(random.choice(string.letters)+random.choice(string.letters)+random.choice(string.letters)+random.choice(string.letters)) 

q = 'ab' 

''' 

print "reference: " 
print round(min(timeit.Timer("q in lst", setup=setup).repeat(7,500)),5) 
# 0.05435 

print "\nreference with joined string: " 
print round(min(timeit.Timer("q+'~' in '~'.join(lst) + '~'", setup=setup).repeat(7,500)),5) 
# 0.05462 

print "\nendswith, with list approach: " 
print round(min(timeit.Timer("any([k for k in lst if k.endswith(q)])", setup=setup).repeat(7,500)),5) 
# 0.62998 

print "\nfind method: " 
print round(min(timeit.Timer("[k for k in lst if k.find(q, len(k)-len(q))]", setup=setup).repeat(7,500)),5) 
# 1.22274 

print "\nregex: " 
print round(min(timeit.Timer("[k for k in lst if re.search(q + '$', k)]", setup=setup).repeat(7,500)),5) 
# 3.73494 

print "\nregex without list comprehension: " 
print round(min(timeit.Timer("re.search(q + '~', '~'.join(lst) + '~')", setup=setup).repeat(7,500)),5) 
# 0.05435 

print "\nendswith, with generator approach: " 
print round(min(timeit.Timer("any((k for k in lst if k.endswith(q)))", setup=setup).repeat(7,500)),5) 
# 0.02052 
+0

非常好。我不知何故在連接中忘記了'q +'〜',並且在將結果與代碼中的生成器進行比較後,我發現這是最好的方法。謝謝:) – vedar

+1

發生器中的any()'是個不錯的主意,但通常在我的循環中沒有命中,所以它不像'q +'〜'in' – vedar