Linq distinct with lambda

Linq Distinct function accepts an IEqualityComparer<T> used to compare values of the IEnumerable to remove “equal” objects to implement the Distinct() function. Sometimes it is more useful to specify a simple Func<T, T, Boolean>, a simple predicate that will implement the concept of Equality between elements. To support such a scenario you can write this simple Extension method.

   1: public static IEnumerable<T> Distinct<T>(

   2:     this IEnumerable<T> source,

   3:     Func<T, T, Boolean> comparer)

   4: {

   5:     return new DistinctByLambda<T>(comparer, source);

   6: }

All the work is done by the DistinctByLambda class, that accepts a reference to the original IEnumerable sequence of elements and the predicate to verify for equality. Here is the code.

   1: public class DistinctByLambda<T> : IEnumerable<T>

   2: {

   3:     private Func<T, T, Boolean> _comparer;

   4:  

   5:     private IEnumerable<T> _source;

   6:  

   7:     public DistinctByLambda(Func<T, T, bool> comparer, IEnumerable<T> source)

   8:     {

   9:         _comparer = comparer;

  10:         _source = source;

  11:     }

  12:  

  13:     public IEnumerator<T> GetEnumerator()

  14:     {

  15:         List<T> alreadyFound = new List<T>();

  16:         foreach (T element in _source)

  17:         {

  18:            if (!alreadyFound.Exists(el => _comparer(el, element)))

  19:            {

  20:                alreadyFound.Add(element);

  21:                yield return element;

  22:            }

  23:             

  24:         }

  25:     }

  26:  

  27:     IEnumerator IEnumerable.GetEnumerator()

  28:     {

  29:         return GetEnumerator();

  30:     }

  31: }

The code is really simple, the IEnumerable.GetEnumerator function is implemented with a simple internal list that stores all distinct elements. For each element of the original list, if it is not equal to any element of the original list it is stored in the list and then returned to the caller; if the element is equal to one element in the list, it gets not returned.

You can use the following function in this simple way.

   1: [Test]

   2: public void VerifyDistinctByLambda()

   3: {

   4:     IList<Test> list = new List<Test>() {new Test("a", 11), new Test("a", 12), new Test("b", 12)};

   5:     var result = list.Distinct((t1, t2) => t1.BlaBla == t2.BlaBla);

   6:     Assert.That(result.Count(), Is.EqualTo(2));

   7:     Assert.That(result, Is.EquivalentTo(new List<Test>() {new Test("a", 11), new Test("b", 12)}));

   8: }

I use a simple Test class that contains two properties, and call Distinct with a  function that compare only the BlaBla property. Now you can use lambda with distinct Smile

Alk.

Published by

Ricci Gian Maria

.Net programmer, User group and community enthusiast, programmer – aspiring architect – and guitar player :). Visual Studio ALM MVP

Leave a Reply

Your email address will not be published.