Puoi spiegare qual è la differenza tra HashSet<T>
e List<T>
in .NET?
Forse puoi spiegare con un esempio in quali casi HashSet<T>
dovrebbe essere preferito List<T>
?
Puoi spiegare qual è la differenza tra HashSet<T>
e List<T>
in .NET?
Forse puoi spiegare con un esempio in quali casi HashSet<T>
dovrebbe essere preferito List<T>
?
Risposte:
A differenza di un elenco <> ...
Un HashSet è un elenco senza membri duplicati.
Poiché un HashSet è vincolato a contenere solo voci univoche, la struttura interna è ottimizzata per la ricerca (rispetto a un elenco): è notevolmente più veloce
L'aggiunta a un HashSet restituisce un valore booleano: false se l'addizione non riesce a causa della già esistente in Set
Può eseguire operazioni su set matematici su un set: Union / Intersezione / IsSubsetOf ecc.
HashSet non implementa IList solo ICollection
Non è possibile utilizzare gli indici con un HashSet, solo gli enumeratori.
Il motivo principale per utilizzare un HashSet sarebbe se sei interessato a eseguire operazioni Set.
Dato 2 set: hashSet1 e hashSet2
//returns a list of distinct items in both sets
HashSet set3 = set1.Union( set2 );
vola in confronto con un'operazione equivalente usando LINQ. È anche più carino scrivere!
Union
metodo. Avevo usato UnionWith
invece.
Per essere più precisi, dimostriamo con esempi,
Non è possibile utilizzare HashSet come nell'esempio seguente.
HashSet<string> hashSet1 = new HashSet<string>(){"1","2","3"};
for (int i = 0; i < hashSet1.Count; i++)
Console.WriteLine(hashSet1[i]);
hashSet1[i]
produrrebbe un errore:
Impossibile applicare l'indicizzazione con [] a un'espressione di tipo "System.Collections.Generic.HashSet"
Puoi usare foreach statement:
foreach (var item in hashSet1)
Console.WriteLine(item);
Non è possibile aggiungere elementi duplicati a HashSet mentre Elenco consente di farlo e mentre si aggiunge un elemento a HashSet, è possibile verificare se contiene o meno l'elemento.
HashSet<string> hashSet1 = new HashSet<string>(){"1","2","3"};
if (hashSet1.Add("1"))
Console.WriteLine("'1' is successfully added to hashSet1!");
else
Console.WriteLine("'1' could not be added to hashSet1, because it contains '1'");
HashSet ha alcune funzioni utili come IntersectWith
, UnionWith
, IsProperSubsetOf
, ExceptWith
, SymmetricExceptWith
etc.
IsProperSubsetOf
:
HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "4" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" };
HashSet<string> hashSet3 = new HashSet<string>() { "1", "2", "3", "4", "5" };
if (hashSet1.IsProperSubsetOf(hashSet3))
Console.WriteLine("hashSet3 contains all elements of hashSet1.");
if (!hashSet1.IsProperSubsetOf(hashSet2))
Console.WriteLine("hashSet2 does not contains all elements of hashSet1.");
UnionWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "3", "4" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" };
hashSet1.UnionWith(hashSet2); //hashSet1 -> 3, 2, 4, 6, 8
IntersectWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "3", "4", "8" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" }
hashSet1.IntersectWith(hashSet2);//hashSet1 -> 4, 8
ExceptWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "5", "6" };
HashSet<string> hashSet2 = new HashSet<string>() { "1", "2", "3", "4" };
hashSet1.ExceptWith(hashSet2);//hashSet1 -> 5, 6
SymmetricExceptWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "5", "6" };
HashSet<string> hashSet2 = new HashSet<string>() { "1", "2", "3", "4" };
hashSet1.SymmetricExceptWith(hashSet2);//hashSet1 -> 4, 5, 6
A proposito, l'ordine non viene conservato negli Hashset. Nell'esempio, abbiamo aggiunto l'ultimo elemento "2" ma è nel secondo ordine:
HashSet<string> hashSet1 = new HashSet<string>() { "3", "4", "8" };
hashSet1.Add("1"); // 3, 4, 8, 1
hashSet1.Remove("4"); // 3, 8, 1
hashSet1.Add("2"); // 3, 2 ,8, 1
A HashSet<T>
è una classe progettata per darti la O(1)
ricerca del contenimento (ovvero, questa raccolta contiene un oggetto particolare e dimmi velocemente la risposta).
A List<T>
è una classe progettata per offrirti una raccolta con O(1)
accesso casuale che può crescere in modo dinamico (pensa ad array dinamici). Puoi testare il contenimento nel O(n)
tempo (a meno che l'elenco non sia ordinato, quindi puoi fare una ricerca binaria nel O(log n)
tempo).
Forse puoi spiegare con un esempio in quali casi
HashSet<T>
dovrebbe essere preferitoList<T>
Quando si desidera testare il contenimento in O(1)
.
Usa a List<T>
quando vuoi:
Se si conosce l'indice dell'oggetto desiderato (anziché il valore dell'articolo stesso) è il recupero O(1)
. Se non si conosce l'indice, la ricerca dell'elemento richiede più tempo, O(n)
per una raccolta non ordinata.
Usa a Hashset<T>
quando vuoi:
Se conosci il nome della cosa che vuoi trovare, Lookup è O(1)
(questa è la parte 'Hash'). Non mantiene un ordine come List<T>
fa e non è possibile archiviare i duplicati (l'aggiunta di un duplicato non ha alcun effetto, questa è la parte 'Imposta').
Un esempio di quando usare a Hashset<T>
sarebbe se vuoi scoprire se una parola giocata in una partita di Scrabble è una parola valida in inglese (o in un'altra lingua). Ancora meglio sarebbe se si volesse creare un servizio Web da utilizzare per tutte le istanze di una versione online di un gioco del genere.
A List<T>
sarebbe una buona struttura di dati per la creazione del tabellone segnapunti per tenere traccia dei punteggi dei giocatori.
Elenco è un elenco ordinato. È
HashSet è un set. It:
L'elenco è più appropriato quando si desidera accedere alla propria raccolta come se fosse come un array a cui è possibile aggiungere, inserire e rimuovere elementi. HashSet è una scelta migliore se si desidera trattare la propria raccolta come una "borsa" di articoli in cui l'ordine non è importante o quando si desidera confrontarlo con altri set utilizzando operazioni come IntersectWith o UnionWith.
L'elenco non è necessariamente unico, mentre l'hashset lo è, per uno.
Una lista è una raccolta ordinata di oggetti di tipo T che a differenza di un array è possibile aggiungere e rimuovere voci.
Dovresti utilizzare un elenco in cui desideri fare riferimento ai membri nell'ordine in cui li hai archiviati e accedi a loro da una posizione anziché dall'elemento stesso.
Un HashSet è come un dizionario che l'articolo stesso è la chiave e il valore, l'ordinamento non è garantito.
Dovresti usare un HashSet dove vuoi controllare che un oggetto sia nella collezione
List
mantiene un ordine (cioè quando le cose sono state aggiunte), ma non ordina automaticamente gli articoli. Dovresti chiamare .Sort
o usare un SortedList
.
Se si decide di applicare queste strutture dati all'utilizzo effettivo nello sviluppo basato sui dati, un HashSet è MOLTO utile nel testare la replica su origini dell'adattatore dati, per la pulizia e la migrazione dei dati.
Inoltre, se si utilizza la classe DataAnnotations, è possibile implementare la logica chiave sulle proprietà della classe e controllare efficacemente un indice naturale (raggruppato o meno) con un HashSet, dove ciò sarebbe molto difficile in un'implementazione dell'elenco.
Un'opzione efficace per l'utilizzo di un elenco è l'implementazione di generici per più supporti su un modello di visualizzazione, come l'invio di un elenco di classi a una vista MVC per un Helper DropDownList e anche per l'invio come costrutto JSON tramite WebApi. L'elenco consente la tipica logica di raccolta di classi e mantiene la flessibilità per un approccio più "interfaccia" come il calcolo di un modello a vista singola su supporti diversi.