我有一个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);
但是这不能编译。有一个巧妙的伎俩吗?
答案 0 :(得分:102)
Distinct将IEqualityComparer作为第二个参数,因此您需要一个IEqualityComparer。然而,制作一个会占用代表的通用的并不难。当然,这可能已经在某些地方实施过,例如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));
答案 1 :(得分:11)
遗憾的是Distinct
没有出现这样的超载,所以你拥有的是一个不错的选择。
使用MoreLinq,您可以使用DistinctBy
运算符。
var distincts = bundle.GetAllThings.DistinctBy(a => a.Id);
您可能还需要考虑编写一个通用的ProjectionEqualityComparer
,它可以将相应的委托转换为IEqualityComparer<T>
实现,例如列出的here。
答案 2 :(得分:2)
此link显示如何创建扩展方法,以便能够以您提供的方式使用Distinct。您需要编写两个Distinct
扩展方法和一个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();
}
}
答案 3 :(得分:-1)
这是我不道德的肮脏的小香草C#技巧:
entities
.GroupBy(e => e.Id)
.Select(g => g.First())