Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use a custom comparer with the Linq Distinct method?

I was reading a book about Linq, and saw that the Distinct method has an overload that takes a comparer. This would be a good solution to a problem I have where I want to get the distinct entities from a collection, but want the comparison to be on the entity ID, even if the other properties are different.

According to the book, if I have a Gribulator entity, I should be able to create a comparer like this...

private class GribulatorComparer : IComparer<Gribulator> {
  public int Compare(Gribulator g1, Gribulator g2) {
    return g1.ID.CompareTo(g2.ID);
  }
}

...and then use it like this...

List<Gribulator> distinctGribulators
  = myGribulators.Distinct(new GribulatorComparer()).ToList();

However, this gives the following compiler errors...

'System.Collections.Generic.List' does not contain a definition for 'Distinct' and the best extension method overload 'System.Linq.Enumerable.Distinct(System.Collections.Generic.IEnumerable, System.Collections.Generic.IEqualityComparer)' has some invalid arguments

Argument 2: cannot convert from 'LinqPlayground.Program.GribulatorComparer' to 'System.Collections.Generic.IEqualityComparer'

I've searched around a bit, and have seen plenty of examples that use code like this, but no complaints about compiler errors.

What am I doing wrong? Also, is this the best way of doing this? I want a one-off solution here, so don't want to start changing the code for the entity itself. I want the entity to remain as normal, but just in this one place, compare by ID only.

Thanks for any help.

like image 729
Avrohom Yisroel Avatar asked Nov 11 '12 14:11

Avrohom Yisroel


People also ask

How does distinct work in Linq?

C# Linq Distinct() method removes the duplicate elements from a sequence (list) and returns the distinct elements from a single data source. It comes under the Set operators' category in LINQ query operators, and the method works the same way as the DISTINCT directive in Structured Query Language (SQL).

Why distinct is not working in Linq?

LINQ Distinct is not that smart when it comes to custom objects. All it does is look at your list and see that it has two different objects (it doesn't care that they have the same values for the member fields). One workaround is to implement the IEquatable interface as shown here.

How do you use distinct methods?

The Distinct<TSource>(IEnumerable<TSource>) method returns an unordered sequence that contains no duplicate values. It uses the default equality comparer, Default, to compare values. In Visual Basic query expression syntax, a Distinct clause translates to an invocation of Distinct.

Does distinct preserve order?

Java Stream distinct() MethodIf the stream is ordered, the encounter order is preserved. It means that the element occurring first will be present in the distinct elements stream.


1 Answers

You're implementing your comparer as an IComparer<T>, the LINQ method overload requires an implementation of IEqualityComparer:

private class GribulatorComparer : IEqualityComparer<Gribulator> {
  public bool Equals(Gribulator g1, Gribulator g2) {
    return g1.ID == g2.ID;
  }
}

edit:

For clarification, the IComparer interface can be used for sorting, as that's basically what the Compare() method does.

Like this:

items.OrderBy(x => new ItemComparer());

private class ItemComparer : IComparer<Item>
{
    public int Compare(Item x, Item y)
    {
        return x.Id.CompareTo(y.Id)
    }
}

Which will sort your collection using that comparer, however LINQ provides a way to do that for simple fields (like an int Id).

items.OrderBy(x => x.Id);
like image 67
Peter Davidsen Avatar answered Sep 21 '22 05:09

Peter Davidsen