简体   繁体   English

Distinct()如何在对象列表中查找唯一元素

[英]Distinct() How to find unique elements in list of objects

There is a very simple class: 有一个非常简单的类:

public class LinkInformation
{
    public LinkInformation(string link, string text, string group)
    {
        this.Link = link;
        this.Text = text;
        this.Group = group;
    }

    public string Link { get; set; }
    public string Text { get; set; }
    public string Group { get; set; }

    public override string ToString()
    {
        return Link.PadRight(70) + Text.PadRight(40) + Group;
    }
}

And I create a list of objects of this class, containing multiple duplicates. 我创建了这个类的对象列表,包含多个重复项。

So, I tried using Distinct() to get a list of unique values. 所以,我尝试使用Distinct()来获取唯一值列表。

But it does not work, so I implemented 但它不起作用,所以我实施了

IComparable<LinkInformation>

    int IComparable<LinkInformation>.CompareTo(LinkInformation other)
    {
        return this.ToString().CompareTo(other.ToString());
    }

and then... 接着...

IEqualityComparer<LinkInformation>

    public bool Equals(LinkInformation x, LinkInformation y)
    {
        return x.ToString().CompareTo(y.ToString()) == 0;
    }

    public int GetHashCode(LinkInformation obj)
    {
        int hash = 17;
        // Suitable nullity checks etc, of course :)
        hash = hash * 23 + obj.Link.GetHashCode();
        hash = hash * 23 + obj.Text.GetHashCode();
        hash = hash * 23 + obj.Group.GetHashCode();
        return hash;
    }

The code using the Distinct is: 使用Distinct的代码是:

    static void Main(string[] args)
    {
        string[] filePath = {   @"C:\temp\html\1.html",
                                @"C:\temp\html\2.html",
                                @"C:\temp\html\3.html",
                                @"C:\temp\html\4.html",
                                @"C:\temp\html\5.html"};

        int index = 0;

        foreach (var path in filePath)
        {
            var parser = new HtmlParser();

            var list = parser.Parse(path);

            var unique = list.Distinct();

            foreach (var elem in unique)
            {
                var full = new FileInfo(path).Name;
                var file = full.Substring(0, full.Length - 5);
                Console.WriteLine((++index).ToString().PadRight(5) + file.PadRight(20) + elem);
            }
        }

        Console.ReadKey();
    }

What has to be done to get Distinct() working? Distinct()工作,必须做些什么?

You need to actually pass the IEqualityComparer that you've created to Disctinct when you call it. 当你调用它时,你需要实际将你创建的IEqualityComparer传递给Disctinct It has two overloads, one accepting no parameters and one accepting an IEqualityComparer . 它有两个重载,一个不接受参数,另一个接受IEqualityComparer If you don't provide a comparer the default is used, and the default comparer doesn't compare the objects as you want them to be compared. 如果您不提供比较器,则使用默认值,并且默认比较器不会比较您希望它们进行比较的对象。

If you want to return distinct elements from sequences of objects of some custom data type, you have to implement the IEquatable generic interface in the class. 如果要从某些自定义数据类型的对象序列中返回不同的元素,则必须在类中实现IEquatable泛型接口。

here is a sample implementation: 这是一个示例实现:

public class Product : IEquatable<Product>
{
    public string Name { get; set; }
    public int Code { get; set; }

    public bool Equals(Product other)
    {

        //Check whether the compared object is null.
        if (Object.ReferenceEquals(other, null)) return false;

        //Check whether the compared object references the same data.
        if (Object.ReferenceEquals(this, other)) return true;

        //Check whether the products' properties are equal.
        return Code.Equals(other.Code) && Name.Equals(other.Name);
    }

    // If Equals() returns true for a pair of objects 
    // then GetHashCode() must return the same value for these objects.

    public override int GetHashCode()
    {

        //Get hash code for the Name field if it is not null.
        int hashProductName = Name == null ? 0 : Name.GetHashCode();

        //Get hash code for the Code field.
        int hashProductCode = Code.GetHashCode();

        //Calculate the hash code for the product.
        return hashProductName ^ hashProductCode;
    }
}

And this is how you do the actual distinct: 这就是你如何做到实际的区别:

Product[] products = { new Product { Name = "apple", Code = 9 }, 
                       new Product { Name = "orange", Code = 4 }, 
                       new Product { Name = "apple", Code = 9 }, 
                       new Product { Name = "lemon", Code = 12 } };

//Exclude duplicates.

IEnumerable<Product> noduplicates =
    products.Distinct();

If you are happy with defining the "distinctness" by a single property, you can do 如果您对通过单个属性定义“清晰度”感到满意,那么您可以这样做

list
    .GroupBy(x => x.Text)
    .Select(x => x.First())

to get a list of "unique" items. 获取“唯一”项目列表。

No need to mess around with IEqualityComparer et al. 无需乱搞IEqualityComparer等。

Without using Distinct nor the comparer, how about: 不使用Distinct和比较器,如何:

list.GroupBy(x => x.ToString()).Select(x => x.First())

I know this solution is not the answer for the exact question, but I think is valid to be open for other solutions. 我知道这个解决方案不是确切问题的答案,但我认为对其他解决方案开放是有效的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM