Python 列表搜索中的快速字符串

Python 列表搜索中的快速字符串,python,string,performance,list,Python,String,Performance,List,使用Python3,我有一个包含100000多个字符串(list1)的列表,每个字符串最多300个字符。我还有一个超过900万子字符串的列表(list2)——我想计算list2中的子字符串出现在其中的元素数。比如说, list1 = ['cat', 'caa', 'doa', 'oat'] list2 = ['at', 'ca', 'do'] 我希望函数返回(映射到列表2): 通常情况下,这是非常简单的,所需的资源非常少。然而,由于列表的巨大规模,我有效率问题。我想找到返回计数器列表的最快方法

使用Python3,我有一个包含100000多个字符串(list1)的列表,每个字符串最多300个字符。我还有一个超过900万子字符串的列表(list2)——我想计算list2中的子字符串出现在其中的元素数。比如说,

list1 = ['cat', 'caa', 'doa', 'oat']
list2 = ['at', 'ca', 'do']
我希望函数返回(映射到列表2):

通常情况下,这是非常简单的,所需的资源非常少。然而,由于列表的巨大规模,我有效率问题。我想找到返回计数器列表的最快方法

我尝试过列表理解、生成器、地图、各种循环,但还没有找到一种快速的方法来完成这项简单的任务。从理论上讲,实现这一目标的最快方法是什么,最好是非常快地采取
O(len(list2))
步骤?

设置
M=len(list1)
N=len(list2)

对于
list2
中的N个条目,您必须与
list1
中的条目进行M个比较。这是最坏的运行时间
O(mxn)
。如果你更进一步,让我们把
list2
中的每个条目的长度设为1,把
list1
中的每个条目的长度设为300,那么你得到的运行时间是
O(300M x N)

如果性能确实是一个问题,请尝试动态编程。这是一个开始:

1) 按长度升序对列表2进行排序,如下所示:

['scorch', 'scorching', 'dump', 'dumpster', 'dumpsters']
2) 将其排序为子列表,使每个前一条目都是前一条目的子集,如下所示:

[['scorch', 'scorching'] , ['dump', 'dumpster', 'dumpsters']]
3) 现在,如果您与
列表1
进行比较,并且
'scorch'
不在其中,那么您也不必搜索
'scorching'
。同样,如果
'dump'
不在其中,则
'dumpster'
'dumpster'


注意,最坏情况下的运行时间仍然是相同的

不确定如何避免使用某种O(n**2)算法。下面是一个简单的实现

>>> def some_sort_of_count(list1, list2):
>>>     return [sum(x in y for y in list1) for x in list2]
>>> 
>>> list1 = ['cat', 'caa', 'doa', 'oat']
>>> list2 = ['at', 'ca', 'do']
>>> some_sort_of_count(list1, list2)
[2, 2, 1]

我相信这个任务可以用机器在线性时间内解决。 有关更多信息,请参见答案(也许你也从该问题的其他答案中获得了一些想法-这几乎是同一个任务,我认为理论上,阿霍·科拉西克是解决这个问题的最快方法)


您必须以这样的方式修改字符串匹配机,即不是返回匹配,而是将每个匹配子字符串的计数器增加1。(这应该只是一个小的修改)。

这是个好主意,但是列表2中的每个子字符串至少在列表1的一个元素中。这将需要大量的开销,但是您可以尝试根据它们所具有的字符对
list1
list2
进行索引,因此,如果
list1
的一个条目是
'abcd'
,那么您不会检查
list2
条目
'efg'
,只有
list2
条目属于
'a'
'b'
'c'
'd'
路径/分支,但会采取相同的步骤,对吗?现在,对于列表2中的每个子字符串,我都按
sum计数(如果子字符串在字符串中,则列表1中的字符串为1)
。检查未包含的字符的过程不会花费与if/in语句相同的时间吗?@user1104160我可能弄错了,但我认为您无法避开最坏的情况
O(300MxN)
。如果这是一个经常被调用的东西,我建议花点时间在一个巨大的树/数组中,根据长度和/或字母列表进行索引,我正试图为你创建一个小例子……伙计,这是一个多么糟糕的度过周五的方式啊
>>> def some_sort_of_count(list1, list2):
>>>     return [sum(x in y for y in list1) for x in list2]
>>> 
>>> list1 = ['cat', 'caa', 'doa', 'oat']
>>> list2 = ['at', 'ca', 'do']
>>> some_sort_of_count(list1, list2)
[2, 2, 1]