query example c# linq distinct

c# - example - Use un delegado para el comparador de igualdad para Distinct de LINQ()



linq query distinct (3)

Distinct toma un IEqualityComparer como segundo argumento, por lo que necesitará un IEqualityComparer. Sin embargo, no es demasiado difícil hacer una versión genérica que tomará un delegado. Por supuesto, esto probablemente ya se haya implementado en algunos lugares, como lo sugirió MoreLINQ en una de las otras respuestas.

Podrías implementar algo como esto:

public static class Compare { public static IEnumerable<T> DistinctBy<T, TIdentity>(this IEnumerable<T> source, Func<T, TIdentity> identitySelector) { return source.Distinct(Compare.By(identitySelector)); } public static IEqualityComparer<TSource> By<TSource, TIdentity>(Func<TSource, TIdentity> identitySelector) { return new DelegateComparer<TSource, TIdentity>(identitySelector); } private class DelegateComparer<T, TIdentity> : IEqualityComparer<T> { private readonly Func<T, TIdentity> identitySelector; public DelegateComparer(Func<T, TIdentity> identitySelector) { this.identitySelector = identitySelector; } public bool Equals(T x, T y) { return Equals(identitySelector(x), identitySelector(y)); } public int GetHashCode(T obj) { return identitySelector(obj).GetHashCode(); } } }

Lo cual te da la sintaxis:

source.DistinctBy(a => a.Id);

O bien, si sientes que está más claro de esta manera:

source.Distinct(Compare.By(a => a.Id));

Tengo una declaración LINQ Distinct () que usa mi propio comparador personalizado, como este:

class MyComparer<T> : IEqualityComparer<T> where T : MyType { public bool Equals(T x, T y) { return x.Id.Equals(y.Id); } public int GetHashCode(T obj) { return obj.Id.GetHashCode(); } } ... var distincts = bundle.GetAllThings.Distinct(new MyComparer<MySubType>());

Todo esto está bien y elegante y funciona como yo quiero. Por curiosidad, ¿necesito definir mi propio Comparador, o puedo reemplazarlo con un delegado? Pensé que debería ser capaz de hacer algo como esto:

var distincts = bundle.GetAllThings.Distinct((a,b) => a.Id == b.Id);

Pero esto no compila. Hay un buen truco?


Es desafortunado que Distinct no tenga esa sobrecarga, por lo que lo que tienes es una buena opción.

Con MoreLinq , puede usar el operador DistinctBy .

var distincts = bundle.GetAllThings.DistinctBy(a => a.Id);

También puede considerar escribir un ProjectionEqualityComparer genérico que pueda convertir al delegado apropiado en una IEqualityComparer<T> , como la que se muestra here .


Este link muestra cómo crear el método de extensión para poder usar Distinct de la manera que usted dio. Tendrá que escribir dos métodos de extensión Distinct y un IEqualityComparer .

Aquí está el código, del sitio:

public static class Extensions { public static IEnumerable<T> Distinct<T>(this IEnumerable<T> source, Func<T, T, bool> comparer) { return source.Distinct(new DelegateComparer<T>(comparer)); } public static IEnumerable<T> Distinct<T>(this IEnumerable<T> source, Func<T, T, bool> comparer, Func<T,int> hashMethod) { return source.Distinct(new DelegateComparer<T>(comparer,hashMethod)); } } public class DelegateComparer<T> : IEqualityComparer<T> { private Func<T, T, bool> _equals; private Func<T,int> _getHashCode; public DelegateComparer(Func<T, T, bool> equals) { this._equals = equals; } public DelegateComparer(Func<T, T, bool> equals, Func<T,int> getHashCode) { this._equals = equals; this._getHashCode = getHashCode; } public bool Equals(T a, T b) { return _equals(a, b); } public int GetHashCode(T a) { if (_getHashCode != null) return _getHashCode(a); else return a.GetHashCode(); } }