HashSet conserva l’ordine di inserimento?

La raccolta HashSet introdotta in .NET 3.5 conserva l’ordine di inserimento quando viene iterata usando foreach ?

La documentazione afferma che la raccolta non è ordinata, ma non dice nulla sull’ordine di inserimento. Un post di blog BCL pre-rilascio afferma che non è ordinato, ma in questo articolo si afferma che è progettato per preservare l’ordine di inserimento. Il mio test limitato suggerisce che l’ordine è conservato, ma potrebbe essere una coincidenza.

Questa pagina HashSet MSDN specifica in modo specifico:

Un set è una raccolta che non contiene elementi duplicati e i cui elementi non sono in ordine particolare.

Penso che l’articolo che afferma di preservare l’ordine sia semplicemente sbagliato. Per i test semplici, l’ordine di inserimento potrebbe essere ben preservato a causa della struttura interna, ma non è garantito e non funzionerà sempre in questo modo. Proverò a inventare un controesempio.

EDIT: Ecco il controesempio:

 using System; using System.Collections.Generic; class Test { static void Main() { var set = new HashSet(); set.Add(1); set.Add(2); set.Add(3); set.Remove(2); set.Add(4); foreach (int x in set) { Console.WriteLine(x); } } } 

Questo stampa 1, 4, 3 nonostante siano stati inseriti 3 prima dei 4.

È ansible che se non rimuovi mai alcun object, verrà mantenuto l’ordine di inserimento. Non sono sicuro, ma non sarei del tutto sorpreso. Tuttavia, penso che sarebbe una pessima idea affidarsi a questo:

  • Non è documentato che funzioni in questo modo e la documentazione afferma esplicitamente che non è ordinato.
  • Non ho esaminato le strutture interne o il codice sorgente (che non ho, ovviamente) – dovrei studiarli attentamente prima di fare qualsiasi richiesta in maniera ferma.
  • L’implementazione potrebbe facilmente cambiare tra le versioni del framework. Affidarsi a questo sarebbe come fare affidamento sull’implementazione della string.GetHashCode non cambiata – cosa che alcuni hanno fatto di nuovo in .NET 1.1 giorni, e poi sono stati masterizzati quando l’implementazione è cambiata in .NET 2.0 …

La documentazione afferma:

Una raccolta HashSet < (Of <(T>)>) non è ordinata e non può contenere elementi duplicati. Se l’ordine o la duplicazione degli elementi è più importante delle prestazioni per l’applicazione, prendere in considerazione l’utilizzo della class List < (Of <(T>)>) insieme al metodo Sort.

Quindi non importa se in realtà mantiene l’ordine degli elementi nell’implementazione corrente, perché non è documentato nel farlo, e anche se ora sembra che questo possa cambiare in qualsiasi momento nel futuro (anche in un hotfix per il quadro).

Si dovrebbe programmare con contratti documentati , non con dettagli di implementazione .

No, un set di hash non manterrà l’ordine di inserimento, almeno non in modo prevedibile. È ansible utilizzare un LinkedHashSet (Java) o un equivalente. Un LinkedHashSet manterrà l’ordine.

Se vuoi ordinare, non dovresti nemmeno usare un set in primo luogo … non è fatto per gli elementi ordinati, tranne in casi eccezionali.

EDIT: sembra che sto predicando: – / Sorry.

Esiste in particolare una SortedSet in .NET4 .

Questo ti darebbe l’ordinamento, ma è improbabile che sia l’ordinamento degli ordini di inserimento. Dal momento che è ansible utilizzare un IComparer personalizzato, in teoria è ansible fare tutto ciò.

Leggendo il codice sorgente per HashSet.AddIfNotPresent è ansible vedere l’ordine di inserimento viene preservato assumendo che non siano state cancellate .

Quindi il new HashSet { "Tom", "Dick", "Harry" } conserva l’ordine, ma se rimuovi Dick e aggiungi Rick, l’ordine sarà [“Tom”, “Rick”, “Harry”].