Paulo Morgado

.NET Development & Architecture

This Blog

Syndication

Search

Tags

News

Unit Test Today! Get Typemock Isolator!

Projects

Books

 

Visitors

Visitor Locations

Community

Email Notifications

Archives

Profile

Disclaimer

The opinions and viewpoints expressed in this site are mine and do not necessarily reflect those of Microsoft, my employer or any community that I belong to. Any code or opinions are offered as is. Products or services mentioned are purchased by me, made available to me by my employer or the manufacturer/vendor which doesn't influence my opinion in any way.

LINQ: Enhancing Distinct With The PredicateEqualityComparer
LINQ With C# (Portuguese)

Today 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:

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:

.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:

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:

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

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

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

Published Thu, Apr 8 2010 2:18 by Paulo Morgado

Filed under: , , , , ,

Comments

# re: LINQ: Enhancing Distinct With The PredicateEqualityComparer@ Thursday, April 08, 2010 8:43 PM

Using the predicate, greatly improves readability, conciseness and expressiveness of the queries, but it can be even better. Most of the times, we don’t want to provide a comparison method but just to extract the comaprison key for the elements.

So, I developed a SelectorEqualityComparer that takes a method that extracts the key value for each element.

msmvps.com/.../linq-enhancing-distinct-with-the-selectorequalitycomparer.aspx

Paulo Morgado

# Using a Delegate/Anonymous Method with the Linq Distinct Extension@ Wednesday, September 08, 2010 12:34 PM

Using a Delegate/Anonymous Method with the Linq Distinct Extension

IT Ramblings

# re: LINQ: Enhancing Distinct With The PredicateEqualityComparer@ Friday, December 02, 2011 1:59 PM

Bela extensão, tive de fazer um distinct em 3 campos com validações distintas e ainda assim no retorno manter todos os campos no meu IQueryable.

Uma mão na roda!

Abraços

Diego Costa

# re: LINQ: Enhancing Distinct With The PredicateEqualityComparer@ Friday, December 02, 2011 2:02 PM

Idk why but I sent you mt comment in portuguese.. no prob I guess.

Well it helped me a lot, I had to distinct all my IQueryable itens by 3 fields, and the return had to be with all fields.

With your extension I could just distinct the fields I needed withouth having to create a class or a newlist with only the fields to distinct.

Thanks!

Diego Costa

# re: LINQ: Enhancing Distinct With The PredicateEqualityComparer@ Sunday, December 04, 2011 6:44 PM

Grato por ter ajudado, Diego. :)

Paulo Morgado

Leave a Comment

(required) 
(required) 
(optional)
(required) 
If you can't read this number refresh your screen
Enter the numbers above: