2008-10-08 16 views
397

¿Alguien sabe si hay un buen equivalente a la colección Set de Java en C#? Sé que puedes imitar un conjunto usando Dictionary o HashTable completando pero ignorando los valores, pero esa no es una manera muy elegante.C# Set collection?

+0

Aquí puede encontrar información básica sobre Hashset. http://dotnetk.com/c-hashset-csharp/ –

Respuesta

55

Trate HashSet:

El HashSet (Of 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 ningún orden particular ...

La capacidad de un objeto HashSet (Of T) es la cantidad de elementos que el objeto puede contener. La capacidad de un objeto HashSet (Of T) aumenta automáticamente a medida que se agregan elementos al objeto.

La clase HashSet (Of T) se basa en el modelo de conjuntos matemáticos y proporciona operaciones de conjunto de alto rendimiento similares al acceso a las claves de las colecciones Dictionary(Of TKey, TValue) o Hashtable. En términos simples, la clase HashSet (Of T) se puede considerar como una colección Dictionary(Of TKey, TValue) sin valores.

Un HashSet (Of T) de recogida no está ordenada y no puede contener elementos duplicados ...

+5

Desafortunadamente, los HashSets no se agregaron hasta hace poco. Si estás trabajando en una versión anterior del framework, vas a tener que seguir con tu Dictionary <> o Hashtable munged. –

388

Si está utilizando .NET 3.5, puede utilizar HashSet<T>. Es cierto que .NET no se ocupa de los conjuntos, así como tampoco lo hace Java.

El Wintellect PowerCollections puede ayudar también.

+2

¿Alguien sabe por qué se llama HashSet y no solo Set? – Wouter

+16

Sospecho que Set es una palabra clave en algunos idiomas, lo que podría causar problemas. –

+5

'Set' es una palabra clave en VB. –

11

un vistazo a PowerCollections encima en CodePlex. Además de Set y OrderedSet, tiene algunos otros tipos de colecciones útiles como Deque, MultiDictionary, Bag, OrderedBag, OrderedDictionary y OrderedMultiDictionary.

Para obtener más colecciones, también está el C5 Generic Collection Library.

12

Uso un contenedor alrededor de Dictionary<T, object>, almacenando nulos en los valores. Esto le da a O (1) agregar, buscar y eliminar en las teclas, y para todos los efectos, actúa como un conjunto.

+2

Debe decir que es más o menos equivalente a std :: unordered_set. std :: set está ordenado. Por ejemplo, puede encontrar rápidamente el punto inicial y final de un rango e iterar desde el principio hasta el final, visitando los elementos en orden de tecla. SortedDictionary * es * más o menos equivalente a std :: set. – doug65536

-4

Sé que este es un hilo viejo, pero me encontré con el mismo problema y me pareció que HashSet era muy poco confiable porque dado el mismo valor inicial, GetHashCode() devolvió códigos diferentes. Por lo tanto, pensé, ¿por qué no utilizar una lista y ocultar el método add como esto

public class UniqueList<T> : List<T> 
{ 
    public new void Add(T obj) 
    { 
     if(!Contains(obj)) 
     { 
      base.Add(obj); 
     } 
    } 
} 

Debido List utiliza el método Equals únicamente para determinar la igualdad, se puede definir el método Equals en su tipo T para asegurarse de que obtener los resultados deseados

+10

La razón por la que no desea usar esto es porque 'List.Contains' tiene una complejidad' O (n) ', lo que significa que su método' Add' ahora también se convierte en 'O (n)' complejidad. Suponiendo que la colección interna no necesita ser redimensionada, 'Add' para' List' y 'HashMap' debe ser de complejidad' O (1) '. TLDR: Esto funcionará, pero es hacky y menos eficiente. –

+5

Claro, si sus objetos no devuelven un valor apropiado para GetHashCode, no debe ponerlos en un contenedor basado en hash. Sería mejor arreglar GetHashCode que usar un contenedor menos eficiente. – bmm6o

+0

¿Dónde está el hashing? – mehmet6parmak

97

La estructura de datos HashSet<T>:

estructura de datos HashSet<T> La Biblioteca de clases de Marco se introdujo en el .NET Framework 3.5. Se puede encontrar una lista completa de sus miembros en el MSDN reference page for HashSet<T>.

HashSet<T> es más o menos el modelo de un mathematical set, lo que significa que:

  1. puede contener no hay valores duplicados.

  2. Sus elementos no están en un orden particular; por lo tanto, el tipo no implementa la interfaz IList<T>, pero el más básico es ICollection<T>. Como consecuencia, los elementos dentro de un conjunto hash no se pueden acceder aleatoriamente a través de índices; solo pueden repetirse a través de un enumerador.

  3. Ciertas funciones de ajuste tales como Union, Intersection, IsSubsetOf, IsSupersetOf están disponibles. Estos pueden ser útiles cuando se trabaja con conjuntos múltiples.

Otra diferencia entre HashSet<T> y List<T> es que llamar al método de un conjunto de hash Add(item) devuelve un valor booleano: true si se ha agregado el elemento y false de otro modo (debido a que ya se encuentra en el conjunto).

¿Por qué no List<T>?

Dado que HashSet<T> es simplemente una colección de objetos únicos, es posible que se pregunte por qué tiene que ser una estructura de datos. Un List<T> normal podría tener el mismo comportamiento comprobando si un objeto se encuentra en la lista antes de agregarlo.

La respuesta corta es la velocidad. La búsqueda a través de un List<T> normal se vuelve muy lento muy rápido a medida que se agregan más elementos. A HashSet<T> requiere un diseño de estructura que permita una búsqueda rápida y velocidades de inserción.

Puntos de referencia:

Vamos a comparar la velocidad de rendimiento de un HashSet<T> frente a un List<T>.

Cada prueba consistía en sumar números enteros de 0 a 9.999 para cada colección. Sin embargo, el mod 25 se aplicó a cada número entero. Mod 25 crea los tipos máximos de elementos 25. Dado que se agregaron 10.000 elementos, esto obligó a 400 colisiones a ocurrir, dando a las estructuras de datos la oportunidad de utilizar sus algoritmos de búsqueda. Los tiempos se midieron 3 veces después de 10,000 ensayos y se promediaron.

No preste demasiada atención a los tiempos de ejecución específicos de las pruebas, ya que dependen de mi hardware, pero mire cómo se comparan entre sí.

  Average time [ms] 
---------------------------- 
HashSet<T>    2,290 
List<T>    5,505 

Ahora hagamos elementos de objetos en lugar de tipos primitivos. Escribí una clase rápida Person con tres campos: Name, LastName y ID.Como no incluí ninguna forma específica de comparar objetos, todos los elementos se agregarán sin colisiones. Esta vez, se agregaron 1,000 objetos Person a cada colección para una sola prueba. Se promediaron los tiempos totales de 3 series de 1,000 pruebas.

  Average time [ms] 
---------------------------- 
HashSet<Person>   201 
List<Person>   3,000 

Como se puede ver, la diferencia en los tiempos de ejecución se convierte en astronómico al usar objetos, haciendo que el HashSet<T> ventajosa.

+10

¿No habría 9975 colisiones en lugar de 400? – sparebytes

+1

¡Así es como escribimos grandes respuestas integrales! –

11

Si está utilizando .NET 4.0 o posterior:

En el caso de que usted necesita clasificar a continuación, utilizar SortedSet<T>. De lo contrario, si no lo hace, utilice HashSet<T> ya que es O(1) para operaciones de búsqueda y manipulación. Mientras que SortedSet<T> es O(log n) para operaciones de búsqueda y manipulación.