使用LINQ Distinct()相等比较子的委派

zysjyyx4  于 2022-12-06  发布在  其他
关注(0)|答案(5)|浏览(131)

我有一个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>());

这一切都很好,正如我所希望的那样工作。出于好奇,我是否需要定义自己的比较器,或者可以用一个委托来替换它?我想我应该能够做如下的事情:

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

但这并不能编译。有什么好办法吗?

h7wcgrx3

h7wcgrx31#

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));
f1tvaqid

f1tvaqid2#

不幸的是,Distinct没有提供这样的重载,所以您所拥有的是一个很好的选择。
对于MoreLinq,可以使用DistinctBy运算符。

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

您可能还想考虑编写一个泛型ProjectionEqualityComparer,它可以将适当的委托转换为IEqualityComparer<T>实现,如here所列的实现。

niknxzdl

niknxzdl3#

下面是我的C#小把戏:

entities
    .GroupBy(e => e.Id)
    .Select(g => g.First())
iqxoj9l9

iqxoj9l94#

这个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();
        }
    }
rlcwz9us

rlcwz9us5#

从NET6开始,DistinctBy扩展方法被添加到System.Linq的库中。
例如:

Planet[] planets =
{
    Planet.Mercury,
    Planet.Venus,
    Planet.Earth,
    Planet.Mars,
    Planet.Jupiter,
    Planet.Saturn,
    Planet.Uranus,
    Planet.Neptune,
    Planet.Pluto
};

foreach (Planet planet in planets.DistinctBy(p => p.Type))
{
    Console.WriteLine(planet);
}

// This code produces the following output:
//     Planet { Name = Mercury, Type = Rock, OrderFromSun = 1 }
//     Planet { Name = Jupiter, Type = Gas, OrderFromSun = 5 }
//     Planet { Name = Uranus, Type = Liquid, OrderFromSun = 7 }
//     Planet { Name = Pluto, Type = Ice, OrderFromSun = 9 }

相关问题