什么是迭代HashSet的最快/最安全方法?

17

我对C#还比较新,但是通过论坛的帖子发现在特定情况下使用HashSet而不是List有一些优势。

我的情况并不是要在单个List中存储大量数据,而是经常需要检查其中的成员。

关键在于我确实需要遍历它,但它们存储或检索的顺序实际上并不重要。

我已经阅读过了使用for each循环比for next循环要慢,那么我应该如何以最快的方式解决这个问题呢?

我正在使用列表进行大量迭代,并且在每个位置执行不同的代码。最常见的情况是当前列表包含点坐标,然后我用它们引用一个二维数组,在此基础上根据列表的条件执行某些操作。

我正在进行大量的.Contains()检查,这肯定会影响列表的性能,因此至少比较一下与HashSet的性能会很方便。

编辑:我目前正在使用列表,在多个位置进行迭代,并且在每个位置执行不同的代码。最常见的情况是当前列表包含点坐标,然后我用它们引用一个二维数组,在此基础上根据列表的条件执行某些操作。

如果没有直接回答我的问题,那也没关系,但我认为除了foreach循环之外,可能还有其他遍历HashSet的方法。目前我不知道还有哪些其他方法、它们提供的优势等等。假设还有其他方法,我还假设会有一种通常的首选方法,只有在不适合需求时才会被忽略(我的需求非常基本)。

至于过早地进行优化,我已经知道像我这样使用列表是一个瓶颈。如何解决这个问题是我卡住的地方。但我并不想通过反复测试来重新发明轮子,只是为了发现我已经以最好的方式处理了它(这是一个需要投入超过3个月时间的大型项目,列表无处不在,但肯定有些列表不希望出现重复,其中有很多数据,不需要按任何特定顺序存储等等)。


1
你在这个迭代中计划做什么?执行代码?计数某些东西? - Joachim Isaksson
3
你过早地进行了优化。这并不意味着你完全应该忽略数据结构和代码的性能问题,但如果你需要一个哈希集合的语义,那么下一步就是在程序的上下文中对迭代进行性能分析,并考虑它通常如何运行。如果迭代不是性能瓶颈,那么就继续往下进行,因为它并不值得你花费时间。不要仅仅假设它会成为瓶颈,而是要进行测试。 - Ed S.
1
我对答案一无所知,但我的惯例是最快的方法不一定是最安全的,最安全的方法也不一定是最快的。我相信如果有一种方法既最快又最安全,那么就不需要其他方法了。我可能错了。 - nawfal
你的性能要求是什么?你是否测量了性能?你应该选择最易读的代码,并且仅在确定系统中的某些代码成为性能瓶颈时才进行优化。 - Steven
尝试一下,你会得到更好的(即考虑所有上下文)结果,并且比在这里询问更快。 - harold
4个回答

18

对于索引集合(如数组),foreach循环会增加一些额外的开销。

这主要是因为foreach进行的边界检查比for循环更多。

HashSet没有索引器,所以必须使用枚举器。

在这种情况下,foreach循环是有效的,因为它只在移动到集合时调用MoveNext()方法。

此外,Parallel.ForEach可以显著提高性能,具体取决于循环中正在执行的工作和HashSet的大小。

如前所述,最好进行性能分析。


2

首先,你不应该遍历哈希集来确定其中是否存在某个项。你应该使用哈希集(而不是LINQ)的contains方法。哈希集被设计成不需要查找每个项以查看任何给定值是否在集合中。这就是它在搜索列表时如此强大的原因。


12
他在问题中说他需要能够进行搜索和迭代,而不是迭代来搜索。 - JamieSee
1
我不明白为什么这个被点赞了。问题不是关于搜索,而是关于迭代。 - PNarimani

1

虽然没有严格回答标题中的问题,但更关注您特定的问题:

我会创建自己的Collection对象,该对象在内部同时使用HashSetList。由于可以使用List进行迭代,因此迭代速度很快,由于可以使用HashSet进行Contains检查,因此检查速度很快。只需将其设置为IEnumerable,您就可以在foreach中使用此集合。

缺点是需要更多的内存,但只有两倍的对象引用,而不是两倍的对象。最坏的情况下,它只占用两倍的内存,但您似乎更关心性能。

这样添加、检查和迭代都很快,只有删除仍然是O(N),因为涉及到List

编辑:如果删除也需要是O(1),则使用doubly linked list而不是常规列表,并将hashSet设置为Dictionary<KeyType, Cell>。您可以检查字典是否包含,还可以快速找到其中包含数据的单元格,因此从数据结构中删除很快。


-2

我曾经遇到过同样的问题,HashSet非常适合添加唯一元素,但在for循环中获取元素时非常慢。我通过将HashSet转换为数组,然后在其上运行for循环来解决这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接