Elenco efficiente di stringhe univoche C #


86

Qual è il modo più efficiente per memorizzare un elenco di stringhe ignorando eventuali duplicati? Pensavo che un dizionario potrebbe essere il migliore per inserire stringhe scrivendo dict [str] = false; ed enumerando le chiavi come un elenco. È una buona soluzione?

Risposte:


111

Se stai usando .NET 3.5, HashSet dovrebbe funzionare per te.

La classe HashSet <(Of <(T>)>) fornisce operazioni sugli insiemi ad alte prestazioni. Un set è una raccolta che non contiene elementi duplicati e i cui elementi non sono in un ordine particolare.


5
Ma HashSetperderà l'ordine degli articoli. Una caratteristica che Listfornisce.
aggsol

4
Aggiuntivo: c'è anche SortedSet <T> che è un comodo HashSet ordinato.
WhoIsRich

Si noti inoltre che non è possibile accedere a HashSet tramite indice, ma solo tramite un enumeratore anziché un elenco.
Andrew

23

Puoi cercare di fare qualcosa del genere

var hash = new HashSet<string>();
var collectionWithDup = new []{"one","one","two","one","two","zero"}; 

// No need to check for duplicates as the Add method
// will only add it if it doesn't exist already
foreach (var str in collectionWithDup)
    hash.Add(str);   

33
Non è necessario il controllo Contains con un HashSet. Puoi semplicemente chiamare direttamente il metodo Add e restituirà true o false a seconda che l'elemento esista o meno.
LukeH

1
La risposta deve essere modificata per rimuovere la chiamata a Contiene ridondante. Questo è tutto ciò di cui hai bisogno per far funzionare l'esempio precedente: var collectionWithDup = new [] {"one", "one", "two", "one", "two", "zero"}; var uniqueValues ​​= new HashSet <string> (collectionWithDup);
user3285954

14

Non sono sicuro che questo conti come una buona risposta, ma di fronte alla necessità di un set unico che mantenga l'ordine di inserzione, sono sceso a compromessi con un HashSet e un List fianco a fianco. In questo caso, ogni volta che aggiungi al set, procedi come segue:

if(hashSet.Add(item))
    orderList.Add(item);

Quando rimuovi gli elementi, assicurati di rimuoverli da entrambi. Quindi, fintanto che puoi essere sicuro che nient'altro ha aggiunto elementi all'elenco, avrai un set unico ordinato per inserimento!


10

Puoi anche usare Linq come in:

using System.Linq;

var items = new List<string>() { "one", "one", "two", "one", "two", "zero" };

List<string> distinctItems = items.Distinct().ToList();

8

Usa HashSet, non è necessario controllare .Contains (), aggiungi semplicemente i tuoi elementi nell'elenco e se è duplicato non lo aggiungerà.

   HashSet<int> uniqueList = new HashSet<int>();
   uniqueList.Add(1); // List has values 1
   uniqueList.Add(2);  // List has values 1,2
   uniqueList.Add(1);  // List has values 1,2
   Console.WriteLine(uniqueList.Count); // it will return 2

2

Questo non fa parte dello spazio dei nomi di sistema, ma ho utilizzato Iesi.Collections da http://www.codeproject.com/KB/recipes/sets.aspx con NHibernate. Supporta set con hash insieme a set ordinati, set di dizionari e così via. Poiché è stato utilizzato con NHibernate, è stato ampiamente utilizzato e molto stabile. Anche questo non richiede .Net 3.5


2

Ecco un'altra soluzione senza utilizzare l'estensione HashSet.

var items = new List<string>() { "one", "one", "two", "one", "two", "zero" };
var uniqueItems = items.Where((item, index) => items.IndexOf(item) == index);

È stato adottato da questo thread: javascript - Valori univoci in un array

Test:

using FluentAssertions;

uniqueItems.Count().Should().Be(3);
uniqueItems.Should().BeEquivalentTo("one", "two", "zero");

Test delle prestazioni per List, HashSete SortedSet. 1 milione di iterazioni:

List: 564 ms
HashSet: 487 ms
SortedSet: 1932 ms

Codice sorgente di prova (sintesi)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.