tags:

views:

318

answers:

3

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.

+3  A: 

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

Hans Passant
+5  A: 

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);
Jon Skeet
would have selected as answer but for the 2 mins early reply from Hans.
Bhaskar
+1  A: 

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()));
Anthony Pegram