Home > Software engineering >  C# Comparing 2 lists using Except doesn't give expected result
C# Comparing 2 lists using Except doesn't give expected result

Time:03-23

So I have 2 lists:

...
List1= new ObservableCollection<Article>();
var List2= new List<Article>();

I want to get the one object that is different in my 2 lists. So in list 1 there is ALWAYS 1 item that is different or you can only find it in this list. I want to compare list1 and list 2 and get that item. So:

  • That item can be an item that is only in list1 is not in list2, see example 1.
  • That item can be an item that has a different quantity than list2, see example 2.

Example 1:

List1= new ObservableCollection<Article>();
var List2= new List<Article>();

List1.Add(new Article(1, "Cola", "1 x"));  
List1.Add(new Article(2, "Ice tea", "1 x"));  
List2.Add(new Article(1, "Cola", "1 x"));  

//Now I want to only get the ice tea back, that is the only difference in my 2 lists.

Example 2:

List1= new ObservableCollection<Article>();
var List2= new List<Article>();

List1.Add(new Article(1, "Cola", "1 x"));  
List1.Add(new Article(2, "Ice tea", "2 x"));  
List2.Add(new Article(1, "Cola", "1 x"));  
List2.Add(new Article(2, "Ice tea", "1 x"));  

//Now I want to only get the ice tea back with "2 x" fromlist 1, that is the only difference in my 2 lists.

I made the following solution but this doesnt work, anyone know what I am doing wrong?

var OldArticles = List1;
var Newarticles = List2;
var PressedItem = OldArticles.Except(Newarticles).ToList();

CodePudding user response:

With all methods which have to compare something you need to remember that your custom class has to override Equals and GetHashCode meaningfully. It's good practise to implement both methods in general but absolutely necessary if you use a set based method like Enumerable.Except which uses first GetHashCode and then Equals.

Another approach is to implement IEquatable<Article> in your class and implement Equals and GetHashCode meaningfully.

A third option is to implement a custom IEqualityComparer<Article> which implements Equals and GetHashCode meaningfully. You can use an instance of it in the overload of many LINQ methods like Except.

Presuming there is an identifier like Id:

public class Article: IEquatable<Article>
{
    // ...
    public int Id { get; }
    
    public bool Equals(Article other)
    {
        return other?.Id == Id;
    }
    
    public override bool Equals(object other)
    {
        return Equals(other as Article);
    }
    
    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}

CodePudding user response:

Enumerable.Except Method returns the members of the first list that don't appear in the second list.

In your case, the 2 lists have no common element, because the elements are reference type and their references are different in 1st list compared to 2nd list although their values are the same.

Use Enumerable.Except either to compare value types or use references when you Add elements in your list rather than Add(new Article(1, "Cola", "1 x"))

The following works:

// create elements
Article a1 = new Article(1, "Cola", "1 x");
Article a2 = new Article(2, "Ice tea", "1 x");
Article a3 = new Article(2, "Ice tea", "2 x");

// Example 1
List1.Add(a1);
List1.Add(a2);
List2.Add(a1);
var PressedItems = List1.Except(List2).ToList();

// Example 2
List1.Add(a1);
List1.Add(a3);
List2.Add(a1);
List2.Add(a2);
PressedItems = List1.Except(List2).ToList();
  • Related