LinQ与自定义比较器不同,留下重复项 [英] LinQ distinct with custom comparer leaves duplicates

查看:82
本文介绍了LinQ与自定义比较器不同,留下重复项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下课程:

public class SupplierCategory : IEquatable<SupplierCategory>
{
    public string Name { get; set; }
    public string Parent { get; set; }

    #region IEquatable<SupplierCategory> Members

    public bool Equals(SupplierCategory other)
    {
        return this.Name == other.Name && this.Parent == other.Parent;
    }

    #endregion
}

public class CategoryPathComparer : IEqualityComparer<List<SupplierCategory>>
{
    #region IEqualityComparer<List<SupplierCategory>> Members

    public bool Equals(List<SupplierCategory> x, List<SupplierCategory> y)
    {
        return x.SequenceEqual(y);
    }

    public int GetHashCode(List<SupplierCategory> obj)
    {
        return obj.GetHashCode();
    }

    #endregion
}

我正在使用以下linq查询:

And i'm using the following linq query:

CategoryPathComparer comparer = new CategoryPathComparer();
List<List<SupplierCategory>> categoryPaths = (from i in infoList
                                                          select
                                                            new List<SupplierCategory>() { 
                                                             new SupplierCategory() { Name = i[3] },
                                                             new SupplierCategory() { Name = i[4], Parent = i[3] },
                                                             new SupplierCategory() { Name = i[5], Parent = i[4] }}).Distinct(comparer).ToList();

但是不同的代码并不能满足我的要求,如以下代码所示:

But the distinct does not do what I want it to do, as the following code demonstrates:

comp.Equals(categoryPaths[0], categoryPaths[1]); //returns True

我是否以错误的方式使用它?为什么不将它们与我的预期相提并论?

Am I using this in a wrong way? why are they not compared as I intend them to?

为了演示比较器的工作原理,以下代码应返回true:

To demonstrate the the comparer does work, the following returns true as it should:

List<SupplierCategory> list1 = new List<SupplierCategory>() {
    new SupplierCategory() { Name = "Cat1" },
    new SupplierCategory() { Name = "Cat2", Parent = "Cat1" },
    new SupplierCategory() { Name = "Cat3", Parent = "Cat2" }
};
List<SupplierCategory> list1 = new List<SupplierCategory>() {
    new SupplierCategory() { Name = "Cat1" },
    new SupplierCategory() { Name = "Cat2", Parent = "Cat1" },
    new SupplierCategory() { Name = "Cat3", Parent = "Cat2" }
};
CategoryPathComparer comp = new CategoryPathComparer();
Console.WriteLine(comp.Equals(list1, list2).ToString());

推荐答案

您的问题是您没有正确实现IEqualityComparer.

Your problem is that you didn't implement IEqualityComparer correctly.

当您实现 IEqualityComparer<T> 时,您必须实施 GetHashCode ,以便任何两个相等对象具有相同的哈希码.

When you implement IEqualityComparer<T>, you must implement GetHashCode so that any two equal objects have the same hashcode.

否则,您将得到不正确的行为,如此处所见.

Otherwise, you will get incorrect behavior, as you're seeing here.

您应按以下方式实现GetHashCode :(由

You should implement GetHashCode as follows: (courtesy of this answer)

public int GetHashCode(List<SupplierCategory> obj) {
    int hash = 17;

    foreach(var value in obj)
        hash = hash * 23 + obj.GetHashCode();

    return hash;
}

您还需要覆盖SupplierCategory中的GetHashCode以保持一致.例如:

You also need to override GetHashCode in SupplierCategory to be consistent. For example:

public override int GetHashCode() {
    int hash = 17;
    hash = hash * 23 + Name.GetHashCode();
    hash = hash * 23 + Parent.GetHashCode();
    return hash;
}

最后,尽管不需要,但您可能应该覆盖SupplierCategory中的Equals,并使其调用为IEquatable实现的Equals方法.

Finally, although you don't need to, you should probably override Equals in SupplierCategory and make it call the Equals method you implemented for IEquatable.

这篇关于LinQ与自定义比较器不同,留下重复项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆