De forma predeterminada, cuando se usa Distinct, el operador linq usa el método Equals, pero puede usar su propio IEqualityComparer<T>objeto para especificar cuándo dos objetos son iguales con una implementación lógica personalizada GetHashCodey un Equalsmétodo. Recuérdalo:
GetHashCodeno debe usar una comparación de CPU pesada (por ejemplo, use solo algunas comprobaciones básicas obvias) y se usa como el primero para indicar si dos objetos son seguramente diferentes (si se devuelven diferentes códigos hash) o potencialmente iguales (el mismo código hash). En este último caso, cuando dos objetos tienen el mismo código hash, el marco pasará a verificar utilizando el método Equals como una decisión final sobre la igualdad de los objetos dados.
Después de que tenga MyTypey una MyTypeEqualityComparerclase siga el código, no asegúrese de que la secuencia mantenga su orden:
var cmp = new MyTypeEqualityComparer();
var lst = new List<MyType>();
var q = lst.Distinct(cmp);
En la siguiente biblioteca de ciencia , implementé un método de extensión para asegurar que el conjunto de Vector3D mantenga el orden cuando se usa un método de extensión específico DistinctKeepOrder:
sigue el código relevante:
public class Vector3DWithOrder
{
public int Order { get; private set; }
public Vector3D Vector { get; private set; }
public Vector3DWithOrder(Vector3D v, int order)
{
Vector = v;
Order = order;
}
}
public class Vector3DWithOrderEqualityComparer : IEqualityComparer<Vector3DWithOrder>
{
Vector3DEqualityComparer cmp;
public Vector3DWithOrderEqualityComparer(Vector3DEqualityComparer _cmp)
{
cmp = _cmp;
}
public bool Equals(Vector3DWithOrder x, Vector3DWithOrder y)
{
return cmp.Equals(x.Vector, y.Vector);
}
public int GetHashCode(Vector3DWithOrder obj)
{
return cmp.GetHashCode(obj.Vector);
}
}
En resumen, Vector3DWithOrderencapsula el tipo y un entero de orden, mientras que Vector3DWithOrderEqualityComparerencapsula el comparador de tipo original.
y este es el método auxiliar para garantizar que se mantenga el orden
public static IEnumerable<Vector3D> DistinctKeepOrder(this IEnumerable<Vector3D> vectors, Vector3DEqualityComparer cmp)
{
var ocmp = new Vector3DWithOrderEqualityComparer(cmp);
return vectors
.Select((w, i) => new Vector3DWithOrder(w, i))
.Distinct(ocmp)
.OrderBy(w => w.Order)
.Select(w => w.Vector);
}
Nota : una mayor investigación podría permitir encontrar una forma más general (usos de interfaces) y optimizada (sin encapsular el objeto).