Anthony Pegram ha dicho que es el mejor. Use la herramienta correcta para el trabajo. Digo esto porque un Distinct
o HashSet
no es muy diferente cuando se trata de rendimiento. Use un HashSet
cuando la colección siempre contenga solo elementos diferentes. También le dice al programador que no puede agregarle duplicados. Use un List<T>
y .Distinct()
normal cuando tenga que agregar duplicados y eliminar duplicados más tarde. La intención importa
En general,
a) un HashSet no puede hacer ningún bien si va a añadir nuevos objetos a partir db y no se ha especificado una costumbre Equals
de su cuenta. Cada objeto de db puede ser una nueva instancia para su hashset (si está recién iniciando) y eso generará duplicados en la colección. En ese caso, use normal List<T>
.
b) Si tiene un comparador de igualdad definido para hashset, y su colección siempre debe contener solo objetos distintos, use hashset.
c) Si tiene un comparador de igualdad definido para hashset, y solo desea objetos distintos de db, no es necesario que la recopilación solo contenga objetos distintos (es decir, se deben agregar duplicados más adelante), un enfoque más rápido es obtener los elementos de db a hashset y luego devuelve una lista regular de ese hashset.
d) Lo mejor que debe hacer es dar la tarea de eliminar duplicados a la base de datos, esa es la herramienta correcta ¡Y eso es de primera clase!
En cuanto a las diferencias de rendimiento, en mis pruebas siempre encontré que HashSet es más rápido, pero eso es solo marginal. Eso es obvio teniendo en cuenta que con el enfoque de Lista primero debe agregar y luego hacer una distinción en él.
Método de ensayo: A partir de dos funciones generales,
public static void Benchmark(Action method, int iterations = 10000)
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < iterations; i++)
method();
sw.Stop();
MsgBox.ShowDialog(sw.Elapsed.TotalMilliseconds.ToString());
}
public static List<T> Repeat<T>(this ICollection<T> lst, int count)
{
if (count < 0)
throw new ArgumentOutOfRangeException("count");
var ret = Enumerable.Empty<T>();
for (var i = 0; i < count; i++)
ret = ret.Concat(lst);
return ret.ToList();
}
implementación:
var d = Enumerable.Range(1, 100).ToList().Repeat(100);
HashSet<int> hash = new HashSet<int>();
Benchmark(() =>
{
hash.Clear();
foreach (var item in d)
{
hash.Add(item);
}
});
~ 3300 ms
var d = Enumerable.Range(1, 100).ToList().Repeat(100);
List<int> list = new List<int>();
Benchmark(() =>
{
list.Clear();
foreach (var item in d)
{
list.Add(item);
}
list = list.Distinct().ToList();
});
~ 5800 ms
Una diferencia de 2,5 segundos no es malo para una lista de 10000 objetos cuando iterado otros 10000 veces. Para casos normales, la diferencia será apenas perceptible.
El mejor enfoque posible para usted con su diseño actual:
var d = Enumerable.Range(1, 100).ToList().Repeat(100);
HashSet<int> hash = new HashSet<int>();
List<int> list = new List<int>();
Benchmark(() =>
{
hash.Clear();
foreach (var item in d)
{
hash.Add(item);
}
list = hash.ToList();
});
~ 3300 ms
no hay ninguna diferencia significativa, ver ..
Sin relación alguna: después de publicar esta respuesta, tenía curiosidad por saber cuál es el mejor enfoque en eliminando duplicados, de una lista normal.
var d = Enumerable.Range(1, 100).ToList().Repeat(100);
HashSet<int> hash = new HashSet<int>();
List<int> list = new List<int>();
Benchmark(() =>
{
hash = new HashSet<int>(d);
});
~ 3900 ms
var d = Enumerable.Range(1, 100).ToList().Repeat(100);
List<int> list = new List<int>();
Benchmark(() =>
{
list = d.Distinct().ToList();
});
~ 3200 ms
Aquí la herramienta adecuada Distinct
es más rápido que el hacker HashSet
! Tal vez sea la sobrecarga de crear un conjunto de hash.
He probado con varias otras combinaciones similares de los tipos de referencia, sin duplicados en la lista original de etc. Los resultados son consistentes.
+1 para la única respuesta correcta! – nawfal