Reputation: 87
So I am trying to find the difference between 2 lists of type Person. This is the person class:
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;
}
}
and in my code, I create 2 variables, List<Person> list1
and List<Person> list2
.
I fill list1 with the following variables:
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"));
and fill list2 with the following:
list2.Add(new Person(30, "first2", "last2"));
list2.Add(new Person(50, "first4", "last4"));
My goal is to have another list (List<Person> list3
) with list1[0]
and list[2]
since that is what is not included in list2
. I tried using list3 = list1.Except(list2).ToList();
but that just returns a copy of list1
and if i do list3 = list2.Except(list1).ToList();
it returns a copy of list2
. How do I solve this? Am I using Except()
right?
Upvotes: 2
Views: 100
Reputation: 26335
You could also create a IEqualityComparer<T>
class that overrides Equals()
and GetHashCode()
:
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);
}
}
Then pass this comparer to Except
to get the difference:
var list3 = list1.Except(list2, new PersonEqualityComparer());
Full demo on dotnetfiddle.net
Upvotes: 1
Reputation: 982
The underlying issue here is that you need to ask yourself, what makes these objects equal? Just because you have assigned them equal property values, does NOT make them equal. For example, although list1[1]
and list2[0]
, seem identical, they are completely different instances of the Person object. Therefore, you need a way to tell when one Person object is "equal" to another.Generate Equals and GetHashCode method overrides in Visual Studio.
This may help as well also, Overriding Equals in C#
Hope this helps, please mark this as the answer if this does. Good luck! Here is the code which works:
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();
}
}
Upvotes: 4
Reputation: 1029
The equality check used by Except
will be ReferenceEquals (are they literally the same object instance) because this is the default way of comparing objects for equality unless specified otherwise.
If you want Except to compare your Person class by the Age, FirstName, and LastName properties then you need to override the Equals and GetHashCode methods on the Person class.
Once you've done this list1.Except(list2).ToList()
should work
Upvotes: 1