Efficent搜索列表项

时间:2016-07-14 14:50:43

标签: python

我有一个列表lst(包含10K项)和查询字词q,我想查找lst中的任何项目是否以q结尾。

作为参考计时器我设置为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方法的列表理解是瓶颈。

1 个答案:

答案 0 :(得分: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