Click here to Skip to main content
15,879,056 members
Articles / Programming Languages / C# 4.0

LINQ: Enhancing Distinct With The PredicateEqualityComparer

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
15 Apr 2010CPOL 11.4K   2  
LINQ: Enhancing Distinct With The PredicateEqualityComparer

free hit countersToday, I was writing a LINQ query and I needed to select distinct values based on a comparison criteria.

Fortunately, LINQ’s Distinct method allows an equality comparer to be supplied, but, unfortunately, sometimes, this means having to write custom equality comparer.

Because I was going to need more than one equality comparer for this set of tools I was building, I decided to build a generic equality comparer that would just take a custom predicate. Something like this:

C#
public class PredicateEqualityComparer<T> : EqualityComparer<T>
{
    private Func<T, T, bool> predicate;

    public PredicateEqualityComparer(Func<T, T, bool> predicate)
        : base()
    {
        this.predicate = predicate;
    }

    public override bool Equals(T x, T y)
    {
        if (x != null)
        {
            return ((y != null) && this.predicate(x, y));
        }

        if (y != null)
        {
            return false;
        }

        return true;
    }

    public override int GetHashCode(T obj)
    {
        // Always return the same value to force the call to IEqualityComparer<T>.Equals
        return 0;
    }
}

Now I can write code like this:

C#
.Distinct(new PredicateEqualityComparer<Item>((x, y) => x.Field == y.Field))

But I felt that I’d lost all conciseness and expressiveness of LINQ and it doesn’t support anonymous types. So I came up with another Distinct extension method:

C#
public static IEnumerable<TSource> Distinct<TSource>
	(this IEnumerable<TSource> source, Func<TSource, TSource, bool> predicate)
{
    return source.Distinct(new PredicateEqualityComparer<TSource>(predicate));
}

And the query is now written like this:

C#
.Distinct((x, y) => x.Field == y.Field)

Looks a lot better, doesn’t it? And it works with anonymous types.

Update: I, accidentally, had published the wrong version of the IEqualityComparer<T>.Equals method.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Paulo Morgado
Portugal Portugal

Comments and Discussions

 
-- There are no messages in this forum --