2009-05-28 33 views
75

¿Cuál es la forma más eficiente de almacenar una lista de cadenas ignorando los duplicados? Estaba pensando que un diccionario puede ser lo mejor para insertar cadenas escribiendo dict [str] = false; y enumerar a través de las teclas como una lista. ¿Es esa una buena solución?Lista eficiente de cadenas exclusivas C#

Respuesta

97

Si está utilizando .NET 3.5, el HashSet debería funcionar para usted.

El HashSet < (De < (T>)>) clase proporciona operaciones de conjuntos de alto rendimiento. Un conjunto es una colección que no contiene elementos duplicados, y cuyos elementos no están en un orden particular.

+3

Sin embargo, un 'HashSet' perderá el orden de los elementos. Una característica que proporciona 'List'. – aggsol

+4

Adicional: También hay SortedSet que es un conveniente HashSet ordenado. – WhoIsRich

+0

También tenga en cuenta que no se puede acceder al HashSet a través de un índice, solo a través de un enumerador como opuesto a una lista. – andrew

2

Esto no es parte del espacio de nombres del sistema, pero se han usado Iesi.Collections desde http://www.codeproject.com/KB/recipes/sets.aspx con NHibernate. Tiene soporte para conjunto hash junto con conjunto ordenado, conjunto de diccionario, etc. Dado que se ha usado con NHibernate, se ha usado de manera extensiva y muy estable. Esto también no requiere .Net 3.5

17

Usted puede mirar a hacer algo como esto

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); 
+32

No necesita la verificación de Contiene con un HashSet.Puede llamar directamente al método Add y devolverá true o false dependiendo de si el elemento ya existe o no. – LukeH

+1

La respuesta debe editarse para eliminar la llamada a Consoportes redundantes. Esto es todo lo que necesita para que el ejemplo anterior funcione: var collectionWithDup = new [] {"one", "one", "two", "one", "two", "zero"}; var uniqueValues ​​= new HashSet (collectionWithDup); – user3285954

12

No estoy seguro si esto se considera como una buena respuesta, pero cuando se enfrentan a la necesidad de un conjunto único que mantiene el orden de inserción, me comprometí con un HashSet y una lista uno al lado del otro. En este caso, siempre que se añada al conjunto, haga lo siguiente:

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

Cuando la eliminación de elementos, asegúrese de sacarlos de ambos. Por lo tanto, siempre y cuando pueda estar seguro de que nada más agregó elementos a la lista, ¡tendrá un conjunto único ordenado por inserción!

6

Usa HashSet, no es necesario marcar .Contains(), solo agrega tus elementos en la lista y si está duplicado no lo agregará.

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

Aquí hay otra solución sin usar el HashSet.

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

fue adoptado a partir de este hilo: javascript - Unique values in an array

prueba:

using FluentAssertions; 

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

prueba de rendimiento para List, HashSet y SortedSet. 1 millón de iteraciones:

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

Test source code (gist)

1

También es posible usar LINQ como en:

using System.Linq; 

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

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