user1740381
user1740381

Reputation: 2199

IEqualityComparer in c# not working?

I have an IEqualityComparer in c#:

public class ScheduledTimeComparer : IEqualityComparer<ScheduledTime>
{
    public bool Equals(ScheduledTime x, ScheduledTime y)
    {
        if (x == y) return true;
        if (x == null) return false;
        return GetHashCode(x) == GetHashCode(y);
    }

    public int GetHashCode(ScheduledTime schedule)
    {
        return schedule.Start.GetHashCode() ^ schedule.End.GetHashCode();
    }
}

public class ScheduledTime
{
    public int Start { get; set; }
    public int End { get; set; }
}

I have the following 2 list of ScheduledTimes objects:

List1 = [{ Start = 60, End = 120 }]

List2 = [{ Start = 180, End = 240 }, { Start = 60, End = 120 }]

Now when i use the above mentioned equality comparer like:

//Count should be greater than 0 because both List1 and List2 are not equal
var equal = List1.Except(List2, new ScheduledTimeComparer()).Count == 0;

The Count is always zero, What i am doing wrong ?

Upvotes: 1

Views: 873

Answers (4)

evanmcdonnal
evanmcdonnal

Reputation: 48096

Your comparison works fine, the problem is that you're misusing Except

var equal = List1.Except(List2, new ScheduledTimeComparer()).Count == 0;

This is giving you items in list1 that aren't in list2. List 1 is a subset of list2 so you get nothing back. If you change it to;

var dif = List2.Except(List1, new ScheduledTimeComparer()).ToList();
dif.AddRange(List1.Except(List2, new ScheduleTimeComparer());
if (dif.Count() > 0)
    // the lists are different

Then you will get back 1 item and it will work as you expected.

Upvotes: 2

Tim S.
Tim S.

Reputation: 56536

List1.Except(List2... looks for items that are in List1 but not in List2. It sounds like you want to know if the lists are equal to each other. Here is one way to do that, using SetEquals:

var set1 = new HashSet<ScheduledTime>(List1, new ScheduledTimeComparer());
bool equal = set1.SetEquals(List2);

Also, your Equals and GetHashCode implementations are broken. In Equals, instead of just comparing hash codes, you need to compare values to get accurate answers. And using XOR (^) in GetHashCode is weak, e.g. anything with Start == End will hash to 0 and both of your examples hash to the same value, 68. A better option is to use multiplying by primes and addition to work out the hash codes. Also, since int.GetHashCode() returns the int itself, I omitted it. This will work better:

public class ScheduledTimeComparer : IEqualityComparer<ScheduledTime>
{
    public bool Equals(ScheduledTime x, ScheduledTime y)
    {
        if (x == y) return true;
        if (x == null) return false;
        return x.Start == y.Start && x.End == y.End;
    }

    public int GetHashCode(ScheduledTime schedule)
    {
        unchecked
        {
            return schedule.Start * 31 + schedule.End;
        }
    }
}

Upvotes: 2

Gilthans
Gilthans

Reputation: 1726

List1.Except(List2, new ScheduledTimeComparer()) 

means List1 \ List2 in group terms; that is, take all the elements in List1 not preset in List2. There are no such elements, so the returned result is empty.

Perhaps what you wanted to do is:

List2.Except(List1, new ScheduledTimeComparer())

Which would return a single result.

Upvotes: 0

Lee
Lee

Reputation: 144136

The count should be zero since Except is set difference and there is an element in List2 equal to the single element in List1. The output sequence contains the elements of List1 not in List2, and there are no such elements using your comparer.

Upvotes: 1

Related Questions