HashSet
.NET 3.5 中引入的集合在使用迭代时是否保留插入顺序foreach
?
该文档指出,该集合未排序,但没有说明插入顺序。一个预发布的 BCL博客条目声明它是无序的,但这篇文章声明它旨在保留插入顺序。我有限的测试表明,该顺序被保留,但这可能是巧合。
集合是不包含重复元素且其元素没有特定顺序的集合。
我认为声称它保留排序的文章是完全错误的。对于简单的测试,由于内部结构可能会很好地保留插入顺序,但不能保证并且不会总是以这种方式工作。我会尝试提出一个反例。
编辑:这是反例:
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 2.0 中发生改变时他们被烧毁了......该文档指出:
HashSet<(Of <(T>)>) 集合未排序且不能包含重复元素。如果顺序或元素重复对应用程序而言比性能更重要,请考虑将 List<(Of <(T>)>) 类与 Sort 方法一起使用。
因此,它是否实际上保留了当前实现中元素的顺序并不重要,因为它没有被记录为这样做,即使现在看起来这可能会在未来的任何时候改变(即使在一个修补程序中框架)。
您应该根据记录的合同而不是实施细节进行编程。
.NET4中专门有一个SortedSet<T>
集合。
这会给你排序,但不太可能是插入顺序排序。由于您可以使用自定义IComparer
,因此理论上您可以让它做任何事情。
不,哈希集不会保留插入顺序,至少不可预测。您可以使用 LinkedHashSet (Java) 或等效的。LinkedHashSet 将保持顺序。
如果你想要订购,你甚至不应该首先使用一个集合......它不是为有序元素制作的,除非在特殊情况下。
编辑:听起来我在说教:-/对不起。
阅读HashSet.AddIfNotPresent的源代码,您可以看到插入顺序被保留,假设没有任何删除。
因此new HashSet<string> { "Tom", "Dick", "Harry" }
保留了顺序,但是如果您随后删除 Dick 并添加 Rick,则顺序将是 ["Tom", "Rick", "Harry"]。