[英]Why can't I write if (object is HashSet<>) but it's okay if I write (object.GetType() == typeof(HashSet<>))
[英]Why can't I preallocate a hashset<T>
為什么我不能預先分配一個hashset<T>
?
有時我可能會向其中添加很多元素並且我想消除調整大小。
下面的答案寫於 2011 年。現在在 .NET 4.7.2 和 .NET Core 2.0 中; 它將在 .NET 標准 2.1 中。
這不應該是不可能的,沒有技術上的原因——微軟只是沒有選擇公開具有初始容量的構造函數。
如果您可以調用采用IEnumerable<T>
的構造函數並使用ICollection<T>
的實現,我相信它將使用集合的大小作為初始最小容量。 請注意,這是一個實現細節。 容量只需大到足以存儲所有不同的元素......
編輯:我相信如果容量結果比它需要的大得多,構造函數將在完成找出真正有多少不同元素后修剪多余的部分。
無論如何,如果您有要添加到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);
}
}
更新。 04 朱爾
也可以通過使用反射緩存來增強此代碼。 這里我們 go:
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;
}
}
此功能在4.7.2中添加:
HashSet<T>(Int32)
Initializes a new instance of the HashSet<T> class that is empty,
but has reserved space for capacity items and uses the default
equality comparer for the set type.
使用初始容量初始化 HashSet 的唯一方法是使用實現ICollection<T>
的 class 的實例(例如List<T>
)來構造它。 它將調用ICollection<T>
上的 Count 分配足夠的空間來保存集合並將所有元素添加到 HashSet 而不重新分配。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.