Linq Except with custom IEqualityComparer

sgmoore picture sgmoore · Aug 12, 2011 · Viewed 37.7k times · Source

I am trying to find the difference between two generic lists, as in the example below. Even though t1 and t2 contain the same properties, they are not the same object, so I have need to implement an IEqualityComparer.

This appears to be working with this example, but the real class has several other properties and I also need to do the same with a few other class.

So I was wondering if I am re-inventing the wheel?

Is there an easier method of comparing all the properties of two objects? At the moment, I really only need to cope with class containing simple types, but it would be nice I have a comparer that worked with classes that contains instances of other classes.

void Main()
{
    var t1 = new Sizes { Name = "Test" , Size = 1} ;
    var t2 = new Sizes { Name = "Test" , Size = 1} ;

    var list1 = new List<Sizes>();
    var list2 = new List<Sizes>();
    list1.Add(t1);
    list2.Add(t2);

    var differences = list2.Except(list1 , new SizesComparer());    
    // differences should be empty.
}


public class Sizes  
{
    public string Name { get;  set; }
    public int    Size { get;  set; }
}

public class SizesComparer : IEqualityComparer<Sizes>   
{
    bool IEqualityComparer<Sizes>.Equals(Sizes x, Sizes y)
    {            
        return (x.Name.Equals(y.Name) && x.Size.Equals(y.Size));        
    }

    int IEqualityComparer<Sizes>.GetHashCode(Sizes obj)
    {
        if (Object.ReferenceEquals(obj, null))
            return 0;               

        return obj.Name.GetHashCode() + obj.Size;       
    }
}

Answer

Chris Snowden picture Chris Snowden · Aug 12, 2011

You could try something like:

var differences = list2.Where(l2 => 
    !list1.Any(l1 => l1.Name == l2.Name && l1.Size == l2.Size));

Or if you prefer:

var differences = list2.Where(l2 => 
    list1.All(l1 => l1.Name != l2.Name || l1.Size != l2.Size));