Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List<T>.Distinct() in C# - multiple criteria for EqualityComparer?

Tags:

c#

list

distinct

I have a collection of objects which have several properties in each of them. I often need to get a list of distinct values for many properties in this collection. If I implement IEqualityComparer on this type , it gives me one single criteria for getting the distinct objects in the collection. How do I get to be able to call Distinct on multiple criteria for this collection ?

For example ,

  class Product {
    string name ;
    string code ;
    string supplier ;
//etc 
}

Imagine a list of such product objects. Sometimes , I want to get list of distinct names in the list , and at some oter time , a list of distinct supplier . etc. If I call Distinct on a list of these products , based on the way IEqualityComparer is implemented , it will always use the same criteria , which is not going to serve my purpose.

like image 261
Bhaskar Avatar asked Apr 28 '10 15:04

Bhaskar


People also ask

How do I get distinct from a list?

To get unique elements. List<int> myList = list. Distinct(). ToList();

What is list distinct?

Returns a list that contains all the values in list list with duplicates removed.

What is distinct () in C#?

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

What is the distinct function?

The Distinct function evaluates a formula across each record of a table and returns a one-column table of the results with duplicate values removed. The name of the column is Result. Fields of the record currently being processed are available within the formula.


3 Answers

Simply provide different IEqualityComparer implementations for different calls to Distinct. Note the difference between IEquatable and IEqualityComparer - usually a type shouldn't implement IEqualityComparer for itself (so Product wouldn't implement IEqualityComparer<Product>). You'd have different implementations, such as ProductNameComparer, ProductCodeComparer etc.

However, another alternative is to use DistinctBy in MoreLINQ

var distinctProducts = products.DistinctBy(p => p.name);
like image 193
Jon Skeet Avatar answered Nov 02 '22 18:11

Jon Skeet


You can use the Distinct() overload that accepts an IEqualityComparer argument.

like image 29
Hans Passant Avatar answered Nov 02 '22 19:11

Hans Passant


You could also create a comparer that accepts function arguments for the Equals and GetHashCode methods. Something like

class Foo
{
    public string Name { get; set; }
    public int Id { get; set; }
}    

class FooComparer : IEqualityComparer<Foo>
{
    public FooComparer(Func<Foo, Foo, bool> equalityComparer, Func<Foo, int> getHashCode)
    {
        EqualityComparer = equalityComparer;
        HashCodeGenerator = getHashCode;
    }

    Func<Foo, Foo, bool> EqualityComparer;
    Func<Foo, int> HashCodeGenerator;

    public bool Equals(Foo x, Foo y)
    {
        return EqualityComparer(x, y);
    }

    public int GetHashCode(Foo obj)
    {
        return HashCodeGenerator(obj);
    }
}

...

List<Foo> foos = new List<Foo>() { new Foo() { Name = "A", Id = 4 }, new Foo() { Name = "B", Id = 4 } };
var list1 = foos.Distinct(new FooComparer((x, y) => x.Id == y.Id, f => f.Id.GetHashCode()));
like image 21
Anthony Pegram Avatar answered Nov 02 '22 19:11

Anthony Pegram