使用LINQ的Distinct()的相等比较器的委托

Aid*_*dan 46 c# linq distinct

我有一个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>());
Run Code Online (Sandbox Code Playgroud)

这一切都很好,花花公子,按我的意愿工作.出于好奇,我是否需要定义自己的Comparer,还是可以用委托替换它?我以为我应该可以这样做:

var distincts = bundle.GetAllThings.Distinct((a,b) => a.Id == b.Id);
Run Code Online (Sandbox Code Playgroud)

但这不编译.有一个巧妙的伎俩吗?

dri*_*iis 104

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这给你的语法:

source.DistinctBy(a => a.Id);
Run Code Online (Sandbox Code Playgroud)

或者,如果你觉得这样更清楚:

source.Distinct(Compare.By(a => a.Id));
Run Code Online (Sandbox Code Playgroud)

  • 凉!如果有人错过了你可以这样做:source.DistinctBy(x => new {xA,xB}); (3认同)
  • 完成后,您还可以编写自己的扩展方法来获取委托. (2认同)

Ani*_*Ani 11

不幸的是Distinct,没有出现这样的超载,所以你拥有的是一个不错的选择.

使用 MoreLinq,您可以使用DistinctBy运算符.

var distincts = bundle.GetAllThings.DistinctBy(a => a.Id); 
Run Code Online (Sandbox Code Playgroud)

您可能还需要考虑编写一个ProjectionEqualityComparer可以将适当的委托转换为IEqualityComparer<T>实现的泛型,例如此处列出的实现.


Eri*_*ric 7

这是我的邪恶肮脏的普通 C# 技巧:

entities
    .GroupBy(e => e.Id)
    .Select(g => g.First())
Run Code Online (Sandbox Code Playgroud)

  • 根据 /sf/answers/82871421/ - 您实际上可以将其简化为单个 GroupBy 调用。它有一个重载,您可以在其中提供选择器:`entities.GroupBy(e =&gt; e.Id, (id, g) =&gt; g.First())` (3认同)