【问题标题】:How to find difference between lists?如何找到列表之间的差异?
【发布时间】:2020-08-25 14:05:35
【问题描述】:

所以我试图找出 2 个 Person 类型列表之间的区别。这是 person 类:

class Person
{
    public int Age { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Person(int age, string firstName, string lastName)
    {
        this.Age = age;
        this.FirstName = firstName;
        this.LastName = lastName;
    }
}

在我的代码中,我创建了 2 个变量,List<Person> list1List<Person> list2

我用以下变量填充 list1:

list1.Add(new Person(20, "first1", "last1"));
list1.Add(new Person(30, "first2", "last2"));
list1.Add(new Person(40, "first3", "last3"));
list1.Add(new Person(50, "first4", "last4"));

并在 list2 中填写以下内容:

list2.Add(new Person(30, "first2", "last2"));
list2.Add(new Person(50, "first4", "last4"));

我的目标是创建另一个列表 (List<Person> list3),其中包含 list1[0]list[2],因为这不是 list2 中包含的内容。我尝试使用list3 = list1.Except(list2).ToList();,但这只会返回list1 的副本,如果我使用list3 = list2.Except(list1).ToList();,它会返回list2 的副本。我该如何解决这个问题?我使用Except() 对吗?

【问题讨论】:

标签: c# list linq generics


【解决方案1】:

您还可以创建一个覆盖Equals()GetHashCode()IEqualityComparer<T> 类:

public class PersonEqualityComparer : IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y)
    {
        if (ReferenceEquals(x, y))
        {
            return true;
        }

        if (x is null || y is null)
        {
            return false;
        }

        return x.Age == y.Age && 
               x.FirstName == y.FirstName && 
               x.LastName == y.LastName;
    }

    public int GetHashCode(Person obj)
    {
        if (obj == null)
        {
            return 0;
        }

        return HashCode.Combine(obj.Age, obj.FirstName, obj.LastName);
    }
}

然后将此比较器传递给Except 以获取差异:

var list3 = list1.Except(list2, new PersonEqualityComparer());

dotnetfiddle.net上的完整演示

【讨论】:

    【解决方案2】:

    这里的根本问题是您需要问自己,是什么让这些对象相等?仅仅因为您为它们分配了相等的属性值,并不会使它们相等。例如,虽然list1[1]list2[0] 看起来相同,但它们是完全不同的 Person 对象实例。因此,您需要一种方法来判断一个 Person 对象何时与另一个“相等”。Generate Equals and GetHashCode method overrides in Visual Studio

    这也可能有帮助,Overriding Equals in C#

    希望这有帮助,如果有,请将其标记为答案。祝你好运! 这是有效的代码:

    class Program
    {
        static void Main(string[] args)
        {
            var list1 = new List<Person>();
            list1.Add(new Person(20, "first1", "last1"));
            list1.Add(new Person(30, "first2", "last2"));
            list1.Add(new Person(40, "first3", "last3"));
            list1.Add(new Person(50, "first4", "last4"));
    
            var list2 = new List<Person>();
            list2.Add(new Person(30, "first2", "last2"));
            list2.Add(new Person(50, "first4", "last4"));
    
            var list3 = list1.Except(list2).ToList();
        }
    }
    
    class Person : IEquatable<Person>
    {
        public int Age { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    
        public Person(int age, string firstName, string lastName)
        {
            this.Age = age;
            this.FirstName = firstName;
            this.LastName = lastName;
        }
    
        public override bool Equals(object obj)
        {
            return Equals(obj as Person);
        }
    
        public bool Equals(Person otherPerson)
        {
            return otherPerson != null && this.Age == otherPerson.Age && this.FirstName == otherPerson.FirstName && this.LastName == otherPerson.LastName;
        }
    
        public override int GetHashCode()
        {
            return this.Age.GetHashCode() + this.FirstName.GetHashCode() + this.LastName.GetHashCode();
        }
    }
    

    【讨论】:

    • 没错。通过使用元组GetHashCode =&gt; (Age, FirstName, LastName).GetHashCode();,您可以用更少的代码获得更好的哈希函数。你也可以对 equals 做同样的事情。
    • 非常感谢,我花了很长时间试图弄清楚为什么它表现得很奇怪。
    • Equals override 应考虑引用相等性并使用ReferenceEquals 方法
    • 我喜欢这个答案,但这里应该澄清一件事。覆盖GetHashCode 的对象应该是不可变的。如果它们的哈希码在其生命周期内发生变化,它会破坏任何使用它们作为键的字典。
    • 或者将GetHashCode的计算限制在不可变的属性上。在这种情况下,没有任何问题,但很容易补救。然而,自定义的 EqualityComparer 可能更适合 IEquatable,因为前者不会被字典隐式使用
    【解决方案3】:

    Except 使用的相等性检查将是 ReferenceEquals(它们实际上是同一个对象实例),因为这是比较对象是否相等的默认方法,除非另有说明。
    如果您想通过 Age、FirstName 和 LastName 属性来比较您的 Person 类,那么您需要覆盖 Person 类的 Equals 和 GetHashCode 方法。

    完成此操作后,list1.Except(list2).ToList() 应该可以工作

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-23
      • 2013-01-02
      • 2013-10-09
      • 2022-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-27
      相关资源
      最近更新 更多