(轉) C#解惑:HashSet<T>類
HashSet<T>
是一個相對“冷門”的類型,平時在項目中用得不多,但是在特定的業務中可以大用。
先來了解下HashSet<T>
類,主要被設計用來存儲集合,做高性能集運算,例如兩個集合求交集、並集、差集等。從名稱可以看出,它是基於Hash的,可以簡單理解為沒有Value的Dictionary。
HashSet<T>
不能用索引訪問,不能存儲重復數據,元素T必須正確實現了Equals
和GetHashCode
。
HashSet<T>
的一些特性如下:
HashSet<T>
中的值不能重復且沒有順序。HashSet<T>
的容量會按需自動添加。
HashSet<T>
的優勢和與List<T>
的比較
HashSet<T>
最大的優勢是檢索的性能,簡單的說它的Contains方法的性能在大數據量時比List<T>
好得多。曾經做過一個測試,將800W條int類型放在List<int>
集合中,使用Contains判斷是否存在,速度巨慢,而放在HashSet<int>
性能得到大幅提升。
在內部算法實現上,HashSet<T>
的Contains方法復雜度是O(1),List<T>
的Contains方法復雜度是O(n),後者數據量越大速度越慢,而HashSet<T>
所以在集合的目的是為了檢索的情況下,我們應該使用HashSet<T>
代替List<T>
。比如一個存儲關鍵字的集合,運行的時候通過其Contains方法檢查輸入字符串是否關鍵字。
在3.5之前,想用哈希表來提高集合的查詢效率,只有Hashtable和Dictionary兩種選擇,而這兩種都是鍵-值方式的存儲。但有些時候,我們只需要其中一個值,例如一個Email集合,如果用泛型哈希表來存儲,往往要在Key和Value各保存一次,不可避免的要造成內存浪費。而HashSet只保存一個值,更加適合處理這種情況。
此外,HashSet的Add方法返回bool值,在添加數據時,如果發現集合中已經存在,則忽略這次操作,並返回false值。而Hashtable和Dictionary碰到重復添加的情況會直接拋出錯誤。
從使用上來看,HashSet和線性集合List更相似一些,但前者的查詢效率有著極大的優勢。假如,用戶註冊時輸入郵箱要檢查唯一性,而當前已註冊的郵箱數量達到10萬條,如果使用List進行查詢,需要遍歷一次列表,時間復雜度為O(n),而使用HashSet則不需要遍歷,通過哈希算法直接得到列表中是否已存在,時間復雜度為O(1),這是哈希表的查詢優勢。
和List的區別
HashSet是Set集合,它只實現了ICollection接口,在單獨元素訪問上,有很大的限制:
跟List相比,不能使用下標來訪問元素,如:list[1] 。
跟Dictionary相比,不能通過鍵值來訪問元素,例如:dic[key],因為HashSet每條數據只保存一項,並不采用Key-Value的方式,換句話說,HashSet中的Key就是Value,假如已經知道了Key,也沒必要再查詢去獲取Value,需要做的只是檢查值是否已存在。
所以剩下的僅僅是開頭提到的集合操作,這是它的缺點,也是特點。
集合運算
IntersectWith (IEnumerable other) (交集)
- public void IntersectWithTest()
- {
- HashSet<int> set1 = new HashSet<int>() { 1, 2, 3 };
- HashSet<int> set2 = new HashSet<int>() { 2, 3, 4 };
- set1.IntersectWith(set2);
- foreach (var item in set1)
- {
- Console.WriteLine(item);
- }
- //輸出:2,3
- }
UnionWith (IEnumerable other) (並集)
public void UnionWithTest()
{
HashSet set1 = new HashSet() { 1, 2, 3 };
HashSet set2 = new HashSet() { 2, 3, 4 };
- set1.UnionWith(set2);
- foreach (var item in set1)
- {
- Console.WriteLine(item);
- }
- //輸出:1,2,3,4
- }
ExceptWith (IEnumerable other) (排除)
public void ExceptWithTest()
{
HashSet set1 = new HashSet() { 1, 2, 3 };
HashSet set2 = new HashSet() { 2, 3, 4 };
- set1.ExceptWith(set2);
- foreach (var item in set1)
- {
- Console.WriteLine(item);
- }
- //輸出:1
- }
(轉) C#解惑:HashSet<T>類