次のように、独自のカスタム比較を使用するLINQ Distinct()ステートメントがあります。
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>());
これはすべて素晴らしく、ダンディで、私が望むように機能します。好奇心から、独自のComparerを定義する必要がありますか、それをデリゲートに置き換えることができますか?私はこのようなことをすることができるはずだと思った:
var distincts = bundle.GetAllThings.Distinct((a,b) => a.Id == b.Id);
しかし、これはコンパイルされません。きちんとしたトリックはありますか?
Distinctは、IEqualityComparerを2番目の引数として受け取るため、IEqualityComparerが必要です。ただし、デリゲートを取る汎用的なものを作成するのはそれほど難しくありません。もちろん、これはおそらく、他の回答の1つで提案されているMoreLINQなど、いくつかの場所で既に実装されています。
次のように実装できます。
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();
}
}
}
構文は次のとおりです。
source.DistinctBy(a => a.Id);
または、この方法がより明確であると感じる場合:
source.Distinct(Compare.By(a => a.Id));
Distinct
がそのようなオーバーロードを思い付かないのは残念なことなので、あなたが持っているのは良い選択肢です。
MoreLinq では、 DistinctBy
演算子を使用できます。
var distincts = bundle.GetAllThings.DistinctBy(a => a.Id);
また、適切なデリゲートを here のようなIEqualityComparer<T>
実装に変換できる汎用のProjectionEqualityComparer
の作成を検討することもできます。
この link は、指定した方法でDistinctを使用できるように拡張メソッドを作成する方法を示しています。 2つのDistinct
拡張メソッドと1つのIEqualityComparer
を記述する必要があります。
サイトからのコードは次のとおりです。
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();
}
}