C # Establecer colección?

488

¿Alguien sabe si hay un buen equivalente a la Setcolección de Java en C #? Sé que puedes imitar un conjunto usando a Dictionaryo a HashTablerellenando pero ignorando los valores, pero esa no es una forma muy elegante.

Omar Kooheji
fuente

Respuestas:

142

Prueba HashSet :

La clase HashSet (Of T) 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 ...

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 conjuntos de alto rendimiento similares al acceso a las teclas de las colecciones Diccionario (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.

Una colección HashSet (Of T) no está ordenada y no puede contener elementos duplicados ...

Leahn Novash
fuente
8
Desafortunadamente, HashSets no se agregaron hasta hace poco. Si está trabajando en una versión anterior del marco, tendrá que seguir con su diccionario <> o Hashtable.
Greg D
413

Si está utilizando .NET 3.5, puede usarlo HashSet<T>. Sin embargo, es cierto que .NET no atiende conjuntos tan bien como Java.

Las Wintellect PowerCollections también pueden ayudar.

Jon Skeet
fuente
16
Sospecho que Set es una palabra clave en algunos idiomas, lo que podría causar problemas.
Jon Skeet
3
@Manish: No, no lo es. Consulte la sección 2.4.3 de la especificación C # 3. Solo tiene un significado especial para las propiedades.
Jon Skeet
28
La razón para llamarlo HashSet, en lugar de solo Set, es la misma que en Java: "Set" describe una interfaz, mientras que "HashSet" describe una implementación, específicamente, este es un Set respaldado por un Hash Map. De esta manera, sabemos (o deberíamos esperar) que la inserción y el acceso deberían tomar el tiempo de acceso O (1), en comparación con un "LinkedListSet" que nos llevaría a esperar que la inserción y el acceso tomaran el tiempo O (n).
David Souther
55
¿a qué te refieres con ".NET no atiende conjuntos tan bien como Java"? ¿Es este conjunto de alguna manera imperfecto en comparación con el de Java?
Louis Rhys
34
@Louis: ¿De qué conjunto estás hablando? Java tiene muchas implementaciones diferentes de Set para diversas situaciones. .NET tenía uno en .NET 3.5 (HashSet) y dos en .NET 4 (HashSet y SortedSet). El hecho de que tuvimos que esperar hasta .NET 3.5 para comenzar es bastante sorprendente.
Jon Skeet
26

Si está utilizando .NET 4.0 o posterior:

En el caso de que necesite ordenar, use SortedSet<T>. De lo contrario, si no lo hace, úselo HashSet<T>ya que es O(1)para operaciones de búsqueda y manipulación. Mientras que SortedSet<T>es O(log n)para buscar y manipular operaciones.

Derek W
fuente
13

Utilizo un contenedor alrededor de un 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.

thecoop
fuente
2
Debe significar que es más o menos equivalente a std :: unordered_set. Se ordena std :: set. 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 teclas. SortedDictionary es más o menos equivalente a std :: set.
doug65536
11

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

Para más colecciones, también está la Biblioteca de colecciones genéricas C5 .

dpan
fuente
-5

Sé que este es un hilo antiguo, pero me encontraba con el mismo problema y descubrí que HashSet era muy poco confiable porque, dado el mismo origen, GetHashCode () devolvió códigos diferentes. Entonces, pensé, ¿por qué no usar una Lista y ocultar el método de agregar como este?

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

Como List usa el método Equals únicamente para determinar la igualdad, puede definir el método Equals en su tipo T para asegurarse de obtener los resultados deseados.

Bob Heck
fuente
13
La razón por la que no querría usar esto es porque List.Containses de O(n)complejidad, lo que significa que su Addmétodo ahora también se vuelve O(n)complejo. Asumiendo que la colección interna no necesita ser redimensionada, Addpara ambosList y HashMapdebe ser O(1)compleja. TLDR: Esto funcionará, pero es hacky y menos eficiente.
Richard Marskell - Drackir
66
Claro, si sus objetos no devuelven un valor apropiado para GetHashCode, no debe colocarlos en un contenedor basado en hash. Sería mejor arreglar GetHashCode que usar un contenedor menos eficiente.
bmm6o