针对大型List <string> </string>测试大量字符串的最有效方法

时间:2011-07-11 15:50:56

标签: c# string linq performance

我已经看了很多其他类似的问题,但是给出的方法对于我想要完成的事情来说似乎太慢了,或者正在测试部分匹配,我不需要它并且应该更慢。

我有两个填充字符串的大文件,我需要检查一个列表中的每个字符串,看它是否与第二个列表中的任何字符串匹配。我不需要检查部分匹配,所有内容都应该正确转义。

第二个列表(要删除的字符串)包含160,000个字符串。我已将其加载到List<String>中,然后读取较大文件的每一行并使用List<String>.Any(line.contains)对其进行测试。

即使只有第一个列表的一小部分(40k字符串),这需要很长时间,可能在我的快速开发计算机上超过20分钟。

这是我的问题

当没有需要部分匹配时,是否有更多/什么是将大型字符串列表与另一个更大的字符串列表进行比较的最有效方法。

6 个答案:

答案 0 :(得分:50)

不使用List<string>,而是使用HashSet<string>。它具有O(1)查找而不是像列表那样的O(n)。如果进行此更改,您应该会看到数量级的加速。

使用HashSet.Contains()而不是LINQ的.Any()扩展方法,也可能会让您获得更好的性能。

答案 1 :(得分:26)

首先,我认为你的逻辑是完全错误的。将委托传递给Contains到Any方法将执行部分字符串匹配,并且您明确声明只需要完全匹配。

除此之外,您的性能问题归因于列表数据结构的性质;它不是为了通过“任何”有效搜索而设计的。

问题在于“Any”只是进行线性搜索,从列表的开头开始,直到找到匹配为止。如果列表有100K条目,则每个“未命中”将进行100K字符串比较,并且每次“命中”将平均进行50K字符串比较。

那太可怕了。

您应该做的是将List转换为字符串的HashSet。该集合占用的内存略多,但非常快速搜索。

另一种可能的优化是对其中一个列表进行排序 - 这是一个O(n lg n)操作 - 然后二进制搜索排序列表,这是一个O(lg n)操作。

第三种可能的优化是对两个列表进行排序,然后编写一个排序列表比较器。显然,排序列表比较器比未排序列表比较器快得多。您将索引保留在每个列表中,并仅前进指向“较小”项的索引。也就是说,如果列表是

A, B, C, D, G, I
B, D, E, H, I

然后从索引指向A和B开始。“A”更小,因此您将第一个索引前进到“B”。现在他们是一样的;你有一场比赛。推进他们两个。第一个索引是“C”,第二个索引是“D”。 “C”更小“,所以推进它......


但更普遍的是,我认为你在过低的水平上描述了这个问题。当你问一个关于洞的问题时,我觉得你问的是关于演习的问题。也许钻头首先不是正确的工具。你能告诉我们为什么你匹配两个大字符串列表?也许有一种更简单的方法来做你想要的。

答案 2 :(得分:3)

使用UnionExcept运算符来获取两个列表之间的差异和相似之处。

联盟: http://msdn.microsoft.com/en-us/library/bb341731.aspx

除外: http://msdn.microsoft.com/en-us/library/system.linq.enumerable.except.aspx

每个函数返回一个包含结果数据的列表。

答案 3 :(得分:3)

我不明白为什么还没有人提到Enumerable.Intersect。这是一个非常有效且非常直接的功能。

答案 4 :(得分:2)

您可以将第一个列表的每个元素插入HashSet<string>,然后测试第二个列表中的每个元素是否存在于集合中。只触及每个项目一次,插入和测试应为O(1)(除非您的数据集由于某种原因是病态的。)

答案 5 :(得分:-1)

字符串是预先知道的,因此排序的矢量将比哈希映射更快。使用字符串友好的哈希值(例如FNV)对较小文件中的字符串进行哈希处理并将它们放入

vector<pair<int, string> >

定义函数以使其在散列上可排序和可比较,然后sort向量。

bool operator < (pair<int, string> const&, pair<int, string> const&) { ... }
bool operator < (pair<int, string> const&, int) { ... }
bool operator < (int, pair<int, string> const&) { ... }

现在从较大的文件中读取每个字符串,对其进行哈希并使用equal_range搜索向量。只比较哈希匹配的完整字符串。 (注意:可能需要额外的魔法才能通过哈希搜索而不是使用虚拟pair<int, string>。)

如果输出开始前的较长延迟是可以接受的并且有足够的空间可用,则将两个文件加载到已排序的向量中,找到匹配的哈希值set_intersection并比较它们的完整字符串可能会更快。我会将细节作为练习留给读者(:-)。请记住,双方都可能存在哈希冲突。