HashSet
.NET 3.5中引入的集合在使用进行迭代时是否保留插入顺序foreach
?
该文档的状态,该集合没有排序,但它并没有说明插入顺序什么。预发布的BCL博客条目指出该条目是无序的,但本文指出该条目旨在保留插入顺序。我的有限测试表明,该顺序得以保留,但这可能是一个巧合。
Answers:
这个HashSet MSDN页面专门说:
集合是不包含重复元素且其元素没有特定顺序的集合。
我认为声称它保留顺序的文章是完全错误的。对于简单的测试,由于内部结构的缘故,插入顺序可能会得到保留,但并不能保证一定会始终如此。我将尝试提出一个反例。
编辑:这是反例:
using System;
using System.Collections.Generic;
class Test
{
static void Main()
{
var set = new HashSet<int>();
set.Add(1);
set.Add(2);
set.Add(3);
set.Remove(2);
set.Add(4);
foreach (int x in set)
{
Console.WriteLine(x);
}
}
}
尽管在4之前插入了3,但仍打印1、4、3。
这是可能的,如果你从来没有删除任何项目,它将保留插入顺序。我不确定,但是我不会完全感到惊讶。但是,我认为依靠它是一个非常糟糕的主意:
string.GetHashCode
不改变执行-这部分人确实早在NET 1.1天,然后在执行他们得到了焚烧确实在.NET 2.0的变化...foreach
不按顺序迭代。始终使用“ for”和索引。
MoveNext
返回调用的任何顺序进行迭代。对于我所知道的每种有序类型,这将与使用索引的顺序相同。请注意,在所讨论的类型(HashSet<T>
)中没有索引器。您能否举一个具体的例子,您认为使用索引比使用foreach循环更好?
该文档指出:
HashSet <(Of <(T>)>)集合未排序,并且不能包含重复的元素。如果顺序或元素重复对于您的应用程序而言比性能更重要,请考虑将List <(Of <(T>)>)类与Sort方法一起使用。
因此,实际上是否保留当前实现中的元素顺序并不重要,因为没有记录这样做,即使现在看来,它在将来的任何时候都可能会改变(即使在框架)。
您应该根据记录在案的合同进行编程,而不是根据实施细节进行编程。
SortedSet<T>
.NET4中专门有一个集合。
这将为您排序,但不太可能是插入顺序排序。由于您可以使用自定义IComparer
,因此从理论上讲,您可以执行此操作。
不,哈希集将无法保留插入顺序,至少无法预测。您可以使用LinkedHashSet(Java)或等效的方法。LinkedHashSet将保留顺序。
如果您要订购,则甚至根本不应该使用集合……除非特殊情况,否则它不是为有序元素而设计的。
编辑:听起来像我在宣讲:-/对不起。
阅读HashSet.AddIfNotPresent的源代码,可以看到假设没有任何删除,插入顺序得以保留。
这样可以new HashSet<string> { "Tom", "Dick", "Harry" }
保留顺序,但是如果您随后删除Dick并添加Rick,则顺序将为[“ Tom”,“ Rick”,“ Harry”]。
new HashSet<int>() { 6, 8 }.ToList()
返回[6,8]但new HashSet<int>() { 8, 6 }.ToList()
返回[8,6]