检查字符串列表中的所有元素是否都在字符串中的最快方法

时间:2018-01-16 09:35:36

标签: python string search string-matching

我有一个字符串

  

"我的名字是安德鲁,我非常棒"。

假设我有一个列表,例如

  

[[' andrew',' name',' awesome'],[' andrew','指定' ;,' awesome']]

我需要我的解决方案才能返回

  

[' andrew',' name',' awesome']

天真的解决方案是:

myString='My name is Andrew, I am pretty awesome'
keywords = [['andrew', 'name', 'awesome'], ['andrew', 'designation', 'awesome']]
results=[]
for i in keywords:
 if all(substring in myString.lower() for substring in i):
    results.append(i)
print results

我的问题是,当列表关键字非常大(比如100000)时,存在性能瓶颈。我需要知道最有效的方法。

1 个答案:

答案 0 :(得分:5)

  

感谢BlackBear pointing out我的时间偏差   因为循环不变量的重新计算。在将它们移出时,事情会发生巨大变化。

有两种方法可以做到这一点。理智的方式,以及正则表达方式。首先,设置。

string = "My name is Andrew, I am pretty awesome"
choices = [['andrew', 'name', 'awesome'], ['andrew', 'designation', 'awesome']]

选项1
这个在列表推导中执行in子字符串检查。 in检查在C中Boyer-Moore algorithm的修改后的实现上运行,速度非常快。

>>> [c for c in choices if all(y in string.lower() for y in c)]
[['andrew', 'name', 'awesome']]

现在,时间安排。但首先,一个小的表现挑剔;您可以将string.lower() 的值缓存在循环之外,它是一个不变量,并且每次都不需要重新计算 -

v = string.lower()
%timeit [c for c in choices if all(y in v for y in c)]
1000000 loops, best of 3: 2.05 µs per loop

选项2
这个使用re.split + set.issuperset;

>>> import re
>>> [c for c in choices if set(re.split('\W', string.lower())).issuperset(c)] 
[['andrew', 'name', 'awesome']]

由于句子中的标点符号,如果要执行集合检查,则无法避免使用re.split

同样,set计算是一个循环不变量,可以移出。这就是它的作用 -

v = set(re.split('\W', string.lower()))
%timeit [c for c in choices if v.issuperset(c)] 
1000000 loops, best of 3: 1.13 µs per loop

这是一个例外情况,我发现正则表达式的执行速度略快。然而,这些时间并不是决定性因素,因为数据的大小和结构差别很大。在得出任何结论之前,我建议您使用自己的数据进行尝试,尽管我的直觉是正则表达式解决方案的扩展性很差。