Cos’è un HashSet<T>?
In .NET, un HashSet<T>
è una collezione che implementa un set non ordinato di elementi unici. Introdotto con la libreria delle collezioni generiche in NET Framework 3.5 , HashSet<T>
beneficia di ulteriori ottimizzazioni per prestazioni, grazie a miglioramenti nell’implementazione interna del framework e possiamo paragonarlo ad un Dizionario dove la chiave è un hash (generato automaticamente) ed il valore è quando gli abbiamo inserito.
Nella programmazione di tutti i giorni andiamo ad utilizzarlo nei casi in cui necessitiamo di una lista i cui elementi devono essere unici. I suoi benefici sono sopratutto
- Prestazioni: Grazie all’uso di una tabella hash, le operazioni comuni come
Contains
hanno una complessità temporale O(1) nella maggior parte dei casi (a differenza delle stringhe che hanno una complessità O(n), poiché la lista deve scansionare tutti gli elementi esistenti). - Univocità: Ideale per collezioni di dati dove è necessario evitare duplicati senza ulteriori verifiche manuali. I duplicati vengono automaticamente eliminati
Vediamo ora alcuni casi pratici per capire meglio il suo funzionamento:
Creazione
Vediamo diversi modi per istanziare un oggetto di tipo HashSet<T>
, nei primi casi passando nel costruttore una lista già esistente, nel secondo aggiungendo elementi man mano.
var stringList = new List<string> { "Alice", "Bob", "Giorgio" };
var hashSet1 = new HashSet<string>(stringList);
var intList = new List<int> { 1, 2, 3, 4, 5 };
var hashSet2 = new HashSet<int>(intList);
var hashSet3 = new HashSet<int>();
hashSet3.Add(1);
hashSet3.Add(2);
hashSet3.Add(3);
hashSet3.Add(4);
Unione di due liste di HashSet<T>
var hashSet1 = new HashSet<int>(new List<int> { 1, 2, 3, 4, 5 });
var hashSet2 = new HashSet<int>(new List<int> { 5, 6, 7, 8, 9 });
hashSet1.UnionWith(hashSet2);
foreach (var item in hashSet1)
{
Console.WriteLine(item);
}
/*
Output:
1
2
3
4
5
6
7
8
9
*/
Intersezione di due liste
Per trovare gli elementi in comune
var hashSet1 = new HashSet<int>(new List<int> { 1, 2, 3, 4, 5 });
var hashSet2 = new HashSet<int>(new List<int> { 3, 4, 5, 6, 7 });
hashSet1.IntersectWith(hashSet2);
foreach (var item in hashSet1)
{
Console.WriteLine(item);
}
/*
Output:
3
4
5
*/
Subset (ExceptWith)
In questo esempio vediamo come ritornare un HashSet<T>
rimuovendo gli elementi presenti un secondo HashSet<T>
:
var hashSet1 = new HashSet<int>(new List<int> { 1, 2, 3, 4, 5 });
var hashSet2 = new HashSet<int>(new List<int> { 3, 4, 5, 6, 7 });
hashSet1.ExceptWith(hashSet2);
foreach (var item in hashSet1)
{
Console.WriteLine(item);
}
/*
Output:
1
2
*/
Eliminazione dei duplicati
Quando viene inizializzato l’oggetto HashSet<T>
con la lista di stringhe verranno automaticamente eliminati i doppioni (Alice è presente 3 volte). Da notare che è presente “Bob” e “bob”.
var list = new List<string> { "Alice", "Bob", "Alice", "Alice", "Giorgio", "bob" };
var hashSet = new HashSet<string>(list);
foreach (var item in hashSet)
{
Console.WriteLine(item);
}
/*
Output:
Alice
Bob
Giorgio
bob
*/
Conclusioni
HashSet<T>
è uno strumento potente, ad alte prestazioni e versatile per gestire collezioni di dati univoci in .NET. Grazie alle sue caratteristiche e al supporto per operazioni sui set, può semplificare molti scenari complessi migliorando le prestazioni.