generic - C#Set colección?
namespace collection c# (10)
Como han mencionado otros, no parece haber una implementación de conjunto en el estándar .NET con semántica de conjunto.
Vea esta pregunta para HashSet
por qué HashSet
no siempre se desea como una implementación de conjunto.
Si está interesado en rodar su propia clase de conjunto, aquí hay un enfoque simple:
public sealed class MathSet<T> : HashSet<T>, IEquatable<MathSet<T>>
{
public override int GetHashCode() => this.Select(elt => elt.GetHashCode()).Sum().GetHashCode();
public bool Equals(MathSet<T> obj) => SetEquals(obj);
public override bool Equals(object obj) => Equals(obj as MathSet<T>);
public static bool operator ==(MathSet<T> a, MathSet<T> b) =>
ReferenceEquals(a, null) ? ReferenceEquals(b, null) : a.Equals(b);
public static bool operator !=(MathSet<T> a, MathSet<T> b) => !(a == b);
}
Ejemplo de uso:
var a = new MathSet<int> { 1, 2, 3 };
var b = new MathSet<int> { 3, 2, 1 };
var c = a.Equals(b); // true
var d = new MathSet<MathSet<int>> { a, b }; // contains one element
var e = a == b; // true
¿Alguien sabe si hay un buen equivalente a la colección Set
de Java en C #? Sé que puedes imitar un conjunto utilizando un Dictionary
o una HashTable
pero ignorando los valores, pero esa no es una forma muy elegante.
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 .
Intente HashSet :
La clase HashSet (Of T) proporciona operaciones de conjunto de alto rendimiento. Un conjunto es una colección que no contiene elementos duplicados, y cuyos elementos no están en ningún orden en particular ...
La capacidad de un objeto HashSet (Of T) es el número 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 claves de las Dictionary(Of TKey, TValue) o Hashtable . En términos simples, la clase HashSet (Of T) se puede considerar como una colección de Dictionary(Of TKey, TValue) sin valores.
Una colección HashSet (Of T) no está ordenada y no puede contener elementos duplicados ...
Podría implementar su propia implementación de conjunto funcional en un par de horas. Usé esto cuando tuve que hacerlo (lo siento, no tengo el código a mano): http://java.sun.com/j2se/1.4.2/docs/api/java/util/Set.html
Sé que este es un subproceso antiguo, pero me estaba topando con el mismo problema y encontré que HashSet no era confiable porque dado el mismo valor inicial, 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);
}
}
}
Debido a que List utiliza 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.
Si está utilizando .NET 3.5, puede usar HashSet . Sin embargo, es cierto que .NET no se ocupa de los conjuntos, al igual que Java.
El Wintellect PowerCollections también puede ayudar.
Utilizo una envoltura alrededor de un Dictionary<T, object>
, almacenando nulos en los valores. Esto le da a O (1) agregar, buscar y eliminar las claves, y para todos los propósitos y propósitos actúa como un conjunto.
Yo uso Iesi.Collections http://www.codeproject.com/KB/recipes/sets.aspx
Se usa en muchos proyectos OSS, primero lo encontré en NHibernate
La estructura de datos HashSet<T>
:
La estructura de datos HashSet<T>
Framework Class Library se introdujo en .NET Framework 3.5. Puede encontrar una lista completa de sus miembros en la HashSet .
HashSet<T>
está más o menos modelado después de un conjunto matemático , lo que significa que:
Puede que no contenga valores duplicados.
Sus elementos no están en ningún orden particular; por lo tanto, el tipo no implementa la interfaz
IList<T>
, sino la más básicaICollection<T>
. Como consecuencia, no se puede acceder aleatoriamente a los elementos dentro de un conjunto de hash a través de índices; solo se pueden iterar a través de un enumerador.Ciertas funciones de conjunto como
Union
,Intersection
,IsSubsetOf
,IsSupersetOf
están disponibles. Estos pueden ser útiles cuando se trabaja con varios conjuntos.
Otra diferencia entre HashSet<T>
y List<T>
es que llamar al método Add(item)
un conjunto hash devuelve un valor booleano: true
si se agregó el elemento, y false
contrario (porque ya se encontró en el conjunto).
¿Por qué no List<T>
?
Dado que un HashSet<T>
es simplemente una colección de objetos únicos, podría preguntarse por qué tiene que ser una estructura de datos. Una List<T>
normal List<T>
podría tener el mismo comportamiento al verificar si un objeto se encuentra en la lista antes de agregarlo.
La respuesta corta es la velocidad. La búsqueda en una List<T>
normal List<T>
vuelve muy lenta muy rápido a medida que se agregan más elementos. Un HashSet<T>
requiere un diseño de estructura que permita búsquedas rápidas y velocidades de inserción.
Puntos de referencia:
Comparemos la velocidad de rendimiento de un HashSet<T>
frente a una List<T>
.
Cada prueba consistió en agregar enteros de 0 a 9,999 a cada colección. Sin embargo, el mod 25 se aplicó a cada entero. El Mod 25 hace los tipos máximos de elementos 25. Desde que se agregaron 10,000 elementos, esto obligó a que ocurrieran 400 colisiones, dando a las estructuras de datos la oportunidad de usar sus algoritmos de búsqueda. Los tiempos se midieron 3 veces después de 10,000 intentos 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 observe cómo se comparan entre sí.
Average time [ms]
----------------------------
HashSet<T> 2,290
List<T> 5,505
Ahora vamos a hacer objetos de elementos en lugar de tipos primitivos. Escribí una clase de Person
rápida con tres campos: Name
, LastName
e 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 única prueba. Los tiempos totales de 3 series de 1,000 intentos se promediaron.
Average time [ms]
----------------------------
HashSet<Person> 201
List<Person> 3,000
Como puede ver, la diferencia en los tiempos de ejecución se vuelve astronómica cuando se usan objetos, lo que hace que HashSet<T>
ventajoso.
Si está utilizando .NET 4.0 o posterior:
En el caso de que necesite una ordenación, use SortedSet<T>
. De lo contrario, si no lo hace, use HashSet ya que es O(1)
para las operaciones de búsqueda y manipulación. Mientras que SortedSet<T>
es O(log n)
para las operaciones de búsqueda y manipulación.