我有2个字符串数组,数组#1包含大约250万个字符串,数组#2包含大约450万个字符串。我需要检查数组#2中的字符串是否在数组#1的字符串中,然后删除它们。
由于"字符串包含另一个字符串"要求,我不能使用任何二进制搜索等,此过程需要30多个小时。
我的意思"字符串包含另一个字符串"例如,数组#1包含一个字符串"游艇",数组#2包含某个地方" house&#34 ;, so" house"在"船屋"这意味着我将不得不删除"游艇"来自阵列#1。
示例(不是实际的,不工作的)代码可以更好地解释它:
for i:=0 to length(array1)-1 do
begin
for j:=0 to length(array2)-1 do
begin
if ansicontainstext(array1[i],array2[j]) then
begin
martrecordtoremove;
break;
end;
end;
end;
所有琴弦大约需要30个小时。
所以我的问题是,有没有办法更快地做到这一点?
答案 0 :(得分:1)
为避免天真的字符串搜索,您必须利用字符串搜索算法来快速搜索文本(wiki)中的整个模式集。
最简单的实现是针对Rabin-Karp算法 在最糟糕的情况下,最好的复杂性是Aho-Corasick。
两个算法的平均情况都很接近,所以首先要为你的目的检查R-K速度是值得的。
另一个可能的问题 - 如何实施martrecordtoremove
?为了有效删除,您应该消除多个内存重新分配。
答案 1 :(得分:1)
你可以进行二分查找,但索引会很大(大约有5000万条目,而不是灾难)。最简单的尝试创建一个sphinxsearch索引,在你内部有一个用于在单词内设置单词的参数(在内部它意味着对于游艇狮身人面像搜索会将这些关键字添加到它的索引中):
houseboat
at
oat
boat
etc..
从搜索返回将是立即的,并且索引的创建应该非常快
答案 2 :(得分:1)
在我看来,问题的一部分是你循环2.5M * 4.5M次。您是否尝试过使用TStringList而不是数组?如果您的数组是TStringList(比如SA1,SA2),您可以编写如下代码:
var
i, j: integer;
begin
SA1.CaseSensitive:=false;
SA2.CaseSensitive:=false;
SA1.Sort;
SA2.Sort;
for i := 0 to SA2.Count-1 do
begin
while true do
begin
//if we delete all the SA1 items, no more processing is required
if SA1.Count=0 then
exit;
//find the occurrence of SA2[i] in SA1
SA1.Find(SA2[i], j);
//Check if the line at item j in SA1 contains the text of SA2[i]
if Pos (SA2[i], SA1[j]) > 0 then //yes, then we delete it
SA1.Delete(j)
else
if (j-1>=0) and (Pos (SA2[i], SA1[j-1]) > 0) then //else check the previous line to see if that has the text
SA1.Delete(j-1)
else
if (j+1<SA1.Count) and (Pos (SA2[i], SA1[j+1]) > 0) then //else check the next line
SA1.Delete(j+1)
else //otherwise break out of while loop
break;
end;
end;
end;
我们在一个不区分大小写(和排序)的转录列表中使用Find。这只通过4.5M项目列表运行一次 - 并且当它继续时从2.5M阵列中删除项目(即SA1在循环期间收缩)。在循环结束时,SA1将只包含您想要的字符串(在SA2中不存在)。也许你应该尝试一下,看看它是否适合你(并希望提高性能)?
希望这会有所帮助。
UPDATE 20170221:我更新了代码,以便在删除之前使用Find查找字符串索引(SA1中的SA2)。我还更新了代码,以便在SA1中出现SA2字符串多次出现的可能性。我还更新了代码,使Stringlist操作不区分大小写。