Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# .NET:如何有效地检查列表中的唯一性<;字符串>;五万件?_C#_.net_List_Collections_Hashset - Fatal编程技术网

C# .NET:如何有效地检查列表中的唯一性<;字符串>;五万件?

C# .NET:如何有效地检查列表中的唯一性<;字符串>;五万件?,c#,.net,list,collections,hashset,C#,.net,List,Collections,Hashset,在某些库代码中,我有一个可以包含50000项或更多项的列表 库的调用者可以调用将字符串添加到列表中的方法。如何有效地检查所添加字符串的唯一性 目前,在添加字符串之前,我扫描了整个列表,并将每个字符串与要添加的字符串进行比较。这将开始显示超过10000项的缩放问题 我将对此进行基准测试,但对洞察感兴趣 如果我用字典替换列表,当列表增加到10000项或更多项时,ContainsKey()是否会明显加快 如果我将唯一性检查推迟到添加所有项目之后,是否会更快?在这一点上,我需要对照其他元素检查每个元素

在某些库代码中,我有一个可以包含50000项或更多项的列表

库的调用者可以调用将字符串添加到列表中的方法。如何有效地检查所添加字符串的唯一性

目前,在添加字符串之前,我扫描了整个列表,并将每个字符串与要添加的字符串进行比较。这将开始显示超过10000项的缩放问题

我将对此进行基准测试,但对洞察感兴趣

  • 如果我用字典替换列表,当列表增加到10000项或更多项时,ContainsKey()是否会明显加快
  • 如果我将唯一性检查推迟到添加所有项目之后,是否会更快?在这一点上,我需要对照其他元素检查每个元素,仍然是一个n^^2操作

编辑

一些基本的基准测试结果。我创建了一个抽象类,它公开了两个方法:Fill和Scan。Fill只是用n个项目填充集合(我使用了50000个)。扫描扫描列表m次(我使用5000次)以查看给定值是否存在。然后,我为List和HashSet分别构建了该类的一个实现

使用的字符串长度统一为11个字符,并通过抽象类中的方法随机生成

一个非常基本的微观基准

Hello from Cheeso.Tests.ListTester
filling 50000 items...
scanning 5000 items...
Time to fill: 00:00:00.4428266
Time to scan: 00:00:13.0291180

Hello from Cheeso.Tests.HashSetTester
filling 50000 items...
scanning 5000 items...
Time to fill: 00:00:00.3797751
Time to scan: 00:00:00.4364431
所以,对于那个长度的字符串,当扫描唯一性时,HashSet大约比List快25倍。此外,对于这种大小的集合,当向集合中添加项时,哈希集对列表的惩罚为零

结果是有趣的,而且是无效的。为了得到有效的结果,我需要做热身间隔,多次试验,随机选择实现。但我相信,这只会稍微改变标准

谢谢大家

EDIT2

在加入随机化和多重试验后,HashSet在本例中的表现始终优于List,约为20倍


对于长度可变、对象更复杂或集合大小不同的字符串,这些结果不一定适用

你应该使用这个类,它是专门为你所做的事情设计的。

使用
HashSet
而不是
List
,那么它应该可以很好地伸缩。

我读到字典是作为关联数组实现的。在某些语言中(不一定与.NET相关),字符串索引存储为树结构,根据节点中的字符在每个节点上分叉。请看

Aho和Corasick在1973年设计了一个类似的数据结构(我想)。如果在这样的结构中存储50000个字符串,那么存储多少字符串并不重要。弦的长度更重要。如果它们的长度大致相同,那么您可能永远不会看到查找速度减慢,因为搜索算法在运行时与您正在搜索的字符串的长度是线性的。即使对于红黑树或AVL树,搜索运行时也更多地取决于正在搜索的字符串的长度,而不是索引中的元素数。但是,如果您选择使用散列函数实现索引键,那么您现在将承担对字符串进行散列(将是O(m),m=字符串长度)以及在索引中查找字符串的成本,其顺序可能是O(log(n)),n=索引中的元素数

编辑:我不是.NET大师。其他更有经验的人提出了另一种结构。我会相信他们的话


编辑2:你的分析有点不适合比较独特性。如果您使用散列结构或字典,那么它将不会是一个O(n^2)操作,因为我在上面发布了推理。如果您继续使用列表,那么它是O(n^2)*(集合中字符串的最大长度)是正确的,因为您每次都必须检查列表中的每个元素。

根据我的测试,
HashSet
list
:)相比不花时间。

是否包含(T)
函数对您不起作用?

可能与主题无关,但如果您想以独立于语言的方式扩展非常大的唯一字符串集(百万以上),您可以查看。

字典肯定会更快,因为它在封面下使用散列。
散列集
会更快,因为它不会为值使用额外的空间。如果您推迟检查,您可以对列表(或副本)进行排序,并根据其相邻项检查每个项。您不需要每个元素都与其他元素相对应。正如大家所建议的那样,
HashSet
可能是最佳选择。然而,如果你需要知道每个键有多少个,你必须回到
字典
之类的地方。迭代顺序重要吗?如果是这样,您将需要在此处搜索类似java.util.LinkedHashSet.NET的对应项:是的,
Add()
方法将返回false,如果元素已经存在于集合中。FIY,在.NET中,字典被实现为哈希表。这不是一个树结构。字符串长度仅在计算哈希时起作用。。。。顺便说一句,它产生O(1)个查找时间。@Martinho这个“散列”是指miller-rabin类型的散列还是我在使用tha-Aho-Corasick存储风格的其他语言中看到的散列类型?这是我的问题。你能给我指一些文件吗?谢谢你纠正我:)直觉说,用字符串查找是不可能的。这样的事情是怎么做到的?即使您正在利用字符串的不变性,您仍然必须检查每个字符,以确定它是否等于永久存储中的字符。有关哈希计算的信息,请参阅wikipedia:。不是你想的那样。至于O(1)部分,实际上它的文档是“非常接近O(1)”,假设一个相当快的散列函数。弦