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 GetHashCode
y un Equals
método. Recuérdalo:
GetHashCode
no 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 MyType
y una MyTypeEqualityComparer
clase 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, Vector3DWithOrder
encapsula el tipo y un entero de orden, mientras que Vector3DWithOrderEqualityComparer
encapsula 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).