¿Puedes explicar cuál es la diferencia entre HashSet<T>
y List<T>
en .NET?
¿Quizás pueda explicar con un ejemplo en qué casos se HashSet<T>
debe preferir List<T>
?
¿Puedes explicar cuál es la diferencia entre HashSet<T>
y List<T>
en .NET?
¿Quizás pueda explicar con un ejemplo en qué casos se HashSet<T>
debe preferir List<T>
?
Respuestas:
A diferencia de una Lista <> ...
Un HashSet es una Lista sin miembros duplicados.
Debido a que un HashSet está limitado a contener solo entradas únicas, la estructura interna está optimizada para la búsqueda (en comparación con una lista): es considerablemente más rápido
Agregar a un HashSet devuelve un valor booleano: falso si la adición falla debido a que ya existe en Set
Puede realizar operaciones de conjuntos matemáticos contra un Conjunto: Unión / Intersección / IsSubsetOf, etc.
HashSet no implementa IList solo ICollection
No puede usar índices con un HashSet, solo enumeradores.
La razón principal para usar un HashSet sería si está interesado en realizar operaciones Set.
Dados 2 conjuntos: hashSet1 y hashSet2
//returns a list of distinct items in both sets
HashSet set3 = set1.Union( set2 );
vuela en comparación con una operación equivalente usando LINQ. ¡También es más ordenado escribir!
Union
método. Había usado en su UnionWith
lugar.
Para ser más precisos, demostremos con ejemplos,
No puede usar HashSet como en el siguiente ejemplo.
HashSet<string> hashSet1 = new HashSet<string>(){"1","2","3"};
for (int i = 0; i < hashSet1.Count; i++)
Console.WriteLine(hashSet1[i]);
hashSet1[i]
produciría un error:
No se puede aplicar la indexación con [] a una expresión de tipo 'System.Collections.Generic.HashSet'
Puede usar cada declaración:
foreach (var item in hashSet1)
Console.WriteLine(item);
No puede agregar elementos duplicados a HashSet mientras List le permite hacer esto y mientras agrega un elemento a HashSet, puede verificar si contiene el elemento o no.
HashSet<string> hashSet1 = new HashSet<string>(){"1","2","3"};
if (hashSet1.Add("1"))
Console.WriteLine("'1' is successfully added to hashSet1!");
else
Console.WriteLine("'1' could not be added to hashSet1, because it contains '1'");
HashSet tiene algunas funciones útiles, como IntersectWith
, UnionWith
, IsProperSubsetOf
, ExceptWith
, SymmetricExceptWith
etc.
IsProperSubsetOf
:
HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "4" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" };
HashSet<string> hashSet3 = new HashSet<string>() { "1", "2", "3", "4", "5" };
if (hashSet1.IsProperSubsetOf(hashSet3))
Console.WriteLine("hashSet3 contains all elements of hashSet1.");
if (!hashSet1.IsProperSubsetOf(hashSet2))
Console.WriteLine("hashSet2 does not contains all elements of hashSet1.");
UnionWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "3", "4" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" };
hashSet1.UnionWith(hashSet2); //hashSet1 -> 3, 2, 4, 6, 8
IntersectWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "3", "4", "8" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" }
hashSet1.IntersectWith(hashSet2);//hashSet1 -> 4, 8
ExceptWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "5", "6" };
HashSet<string> hashSet2 = new HashSet<string>() { "1", "2", "3", "4" };
hashSet1.ExceptWith(hashSet2);//hashSet1 -> 5, 6
SymmetricExceptWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "5", "6" };
HashSet<string> hashSet2 = new HashSet<string>() { "1", "2", "3", "4" };
hashSet1.SymmetricExceptWith(hashSet2);//hashSet1 -> 4, 5, 6
Por cierto, el orden no se conserva en HashSets. En el ejemplo, agregamos el elemento "2" al final pero está en el segundo orden:
HashSet<string> hashSet1 = new HashSet<string>() { "3", "4", "8" };
hashSet1.Add("1"); // 3, 4, 8, 1
hashSet1.Remove("4"); // 3, 8, 1
hashSet1.Add("2"); // 3, 2 ,8, 1
A HashSet<T>
es una clase diseñada para darle una O(1)
búsqueda de contención (es decir, esta colección contiene un objeto en particular y me dice la respuesta rápidamente).
A List<T>
es una clase diseñada para darle una colección con O(1)
acceso aleatorio que puede crecer dinámicamente (piense en una matriz dinámica). Puede probar la contención a O(n)
tiempo (a menos que la lista esté ordenada, entonces puede hacer una búsqueda binaria a O(log n)
tiempo).
Tal vez pueda explicar con un ejemplo en qué casos se
HashSet<T>
debe preferirList<T>
Cuando quieres probar la contención en O(1)
.
Use a List<T>
cuando quiera:
Si conoce el índice del elemento que desea (en lugar del valor del elemento en sí), la recuperación es O(1)
. Si no conoce el índice, la búsqueda del elemento lleva más tiempo O(n)
para una colección sin clasificar.
Use a Hashset<T>
cuando quiera:
Si conoce el nombre de la cosa que desea encontrar, la búsqueda es O(1)
(esa es la parte 'Hash'). No mantiene un orden como lo List<T>
hace y no puede almacenar duplicados (agregar un duplicado no tiene ningún efecto, esa es la parte 'Establecer').
Un ejemplo de cuándo usar un Hashset<T>
sería si desea averiguar si una palabra jugada en un juego de Scrabble es una palabra válida en inglés (u otro idioma). Aún mejor sería si quisieras crear un servicio web para ser utilizado por todas las instancias de una versión en línea de dicho juego.
A List<T>
sería una buena estructura de datos para crear el marcador para seguir los puntajes de los jugadores.
La lista es una lista ordenada. Es
HashSet es un conjunto. Eso:
La lista es más apropiada cuando desea acceder a su colección como si fuera una matriz a la que podría agregar, insertar y eliminar elementos. HashSet es una mejor opción si desea tratar su colección como una "bolsa" de elementos en los que el orden no es importante o cuando desea compararlo con otros conjuntos utilizando las operaciones como IntersectWith o UnionWith.
La lista no es necesariamente única, mientras que el hashset sí lo es.
Una Lista es una colección ordenada de objetos de Tipo T que, a diferencia de una matriz, puede agregar y eliminar entradas.
Usaría una lista en la que desea hacer referencia a los miembros en el orden en que los almacenó y accede a ellos por una posición en lugar del elemento en sí.
Un HashSet es como un diccionario en el que el elemento en sí es la clave, así como el valor, el orden no está garantizado.
Usaría un HashSet donde desea verificar que un objeto esté en la colección
List
mantiene un orden (es decir, cuando se agregaron cosas), pero no clasifica automáticamente los elementos. Tendrías que llamar .Sort
o usar a SortedList
.
Si decide aplicar estas estructuras de datos al uso real en el desarrollo basado en datos, un HashSet es MUY útil para probar la replicación contra fuentes de adaptador de datos, para la limpieza y migración de datos.
Además, si se usa la clase DataAnnotations, se puede implementar la lógica clave en las propiedades de la clase y controlar efectivamente un índice natural (agrupado o no) con un HashSet, donde esto sería muy difícil en una implementación de la lista.
Una opción sólida para usar una lista es implementar genéricos para múltiples medios en un Modelo de vista, como enviar una lista de clases a una Vista MVC para un Ayudante DropDownList, y también para enviar como una construcción JSON a través de WebApi. La lista permite la lógica típica de recopilación de clases y mantiene la flexibilidad para un enfoque más similar a la "Interfaz" para calcular un modelo de vista única para diferentes medios.