为什么我不能预分配一个哈希集<T>

为什么我不能预分配一个hashset<T>

有时候,我可能会添加很多元素,我想消除resize。

没有技术上的原因,为什么这是不可能的 – 微软只是没有select公开一个具有初始能力的构造函数。

如果你可以调用一个带IEnumerable<T>的构造函数,并使用ICollection<T> ,我相信将使用集合的大小作为初始最小容量。 这是一个实现细节,介意你。 容量只有足够大才能存储所有不同的元素…

编辑:我相信,如果容量变得比它需要的大,构造函数将修剪多余的时候,它发现了真正有多less不同的元素。

无论如何,如果你要添加到HashSet<T>的集合它实现ICollection<T> ,然后将它传递给构造函数,而不是一个一个地添加元素将是一个胜利,基本上: )

编辑:一种解决方法将使用一个Dictionary<TKey, TValue>而不是一个HashSet<T> ,只是不使用的值。 这不会在所有情况下工作,因为它不会给你与HashSet<T>相同的接口。

Jon Skeet的回答几乎是完整的。 要用HashSet<int>来解决这个问题,我必须做下面的事情:

 public class ClassUsingHashSet { private static readonly List<int> PreallocationList = Enumerable.Range(0, 10000).ToList(); public ClassUsingHashSet() { this.hashSet = new HashSet<int>(PreallocationList); this.hashSet.Clear(); } public void Add(int item) { this.hashSet.Add(item); } private HashSet<int> hashSet; } 

这个技巧是有效的,因为Clear HashSet之后没有被修剪,如文档中所述:

在调用TrimExcess之前,容量保持不变。

我正在使用此代码来设置HashSet的初始容量。 你可以使用它作为扩展或直接

 public static class HashSetExtensions { private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.NonPublic; public static HashSet<T> SetCapacity<T>(this HashSet<T> hs, int capacity) { var initialize = hs.GetType().GetMethod("Initialize", Flags); initialize.Invoke(hs, new object[] { capacity }); return hs; } public static HashSet<T> GetHashSet<T>(int capacity) { return new HashSet<T>().SetCapacity(capacity); } } 

UPD。 04 jule

此代码也可以通过使用reflectioncaching来增强。 开始了:

 public static class HashSetExtensions { private static class HashSetDelegateHolder<T> { private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.NonPublic; public static MethodInfo InitializeMethod { get; } = typeof(HashSet<T>).GetMethod("Initialize", Flags); } public static void SetCapacity<T>(this HashSet<T> hs, int capacity) { HashSetDelegateHolder<T>.InitializeMethod.Invoke(hs, new object[] { capacity }); } public static HashSet<T> GetHashSet<T>(int capacity) { var hashSet = new HashSet<T>(); hashSet.SetCapacity(capacity); return hashSet; } } 

用初始容量来初始化HashSet的唯一方法是用一个实现ICollection<T>的类(如List<T>的instnace来构造它。 它将在ICollection<T>上调用Count来分配足够的空间来容纳集合,并将所有元素添加到HashSet中而不用重新分配。