为什么我不能预分配一个哈希集<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中而不用重新分配。