A DistinctBy extension that takes a Lambda for Distinct

Wouldn't it be nice to have an extension for Distinct that just takes a comparison function?  That way you could just pass in the lambda comparison into your Distinct method.  After searching on the web, I found a combination of solutions that works pretty well.  This one by Brendan Enrick is perfect for what I need.  I modified it a bit so it works for the Equals Operator.  See below:

First we need to create an IEqualityComparer that takes a lambda expression.  I used Brendan's, but modified GetHashCode so it is ignored and handled in the Equal operator as someone in his blog suggested.


using
System;
using
System.Collections.Generic;
using
System.Linq;

namespace
Ows.Composite.Core
{
public class LambdaComparer<T> : IEqualityComparer<T>
{
private readonly Func<T, T, bool> lambdaComparer;
private readonly Func<T, int> lambdaHash;
public LambdaComparer(Func<T, T, bool> lambdaComparer) :
this(lambdaComparer, o => o.GetHashCode())
{
}
public LambdaComparer(Func<T, T, bool> lambdaComparer, Func<T, int> lambdaHash)
{
if (lambdaComparer == null)
throw new ArgumentNullException("lambdaComparer");
if (lambdaHash == null)
throw new ArgumentNullException("lambdaHash");
this.lambdaComparer = lambdaComparer;
this.lambdaHash = lambdaHash;
}
public bool Equals(T x, T y)
{
return lambdaComparer(x, y);
}
public int GetHashCode(T obj)
{
return 0;
}
}
public static class Ext
{
public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first,
IEnumerable<TSource> second, Func<TSource, TSource, bool> comparer)
{
return first.Except(second, new LambdaComparer<TSource>(comparer));
}
}
}

Next, we can create an extension named DistinctBy that will simply call Distinct with an instance of this lambda comparer called DistinctBy.  We'll write the extension so that we only need to pass in an anonymous delegate to determine equality of our list elements


public static IEnumerable<TSource> DistinctBy<TSource>(this IEnumerable<TSource> items, Func<TSource, TSource, bool> equalityComparer ) where TSource:class
{
  return items.Distinct(new LambdaComparer<TSource>(equalityComparer));
}

That's it! 

Here is an example of how to use our new DistinctBy extension to obtain  a distinct list of people  by name.

var distinctPeople = people.DistinctBy((x, y) => x.Name == y.Name)