tags:

views:

249

answers:

4

Is it possible to get the distinct elements of a List based on a property of the objects in the List?

Someting like: Distinct(x => x.id)

What's not usefull for me is following: .Select(x => x.id).Distinct() because then I would get back a List<int> instead of List<MyClass>

+1  A: 

You need DistinctBy. It's not part of the standard .NET libraries, but Jon Skeet made an implementation of it for Linq to objects here. It's also included in morelinq.

Mark Byers
+2  A: 

That sounds like a grouping construct to me, because you need to decide which of the supposedly identical object you actually want to return

var q = from x in foo
        group x by x.Id into g
        select g.First(); // or some other selection from g

Just because Id is identical across multiple items doesn't mean that the items are identical on other properties, so you need to explicitly decide which item is returned.

Mark Seemann
+2  A: 

What you can do is implement your own IEqualityComparer<T> and pass that to Distinct:

class SomeType {
    public int id { get; set; }
    // other properties
}
class EqualityComparer : IEqualityComparer<SomeType> {
    public bool Equals(SomeType x, SomeType y) {
        return x.id == y.id;
    }

    public int GetHashCode(SomeType obj) {
        return obj.id.GetHashCode();
    }
}

Then:

// elements is IEnumerable<SomeType>
var distinct = elements.Distinct(new EqualityComparer());
// distinct is IEnumerable<SomeType> and contains distinct items from elements
// as per EqualityComparer
Jason
+2  A: 

There is an overload on Enumerable.Distinct() that takes IEqualityComparer.

Here's an example where I used it to filter integers by parity:

    class IntParitiyComparer : IEqualityComparer<int>
    {
        public bool Equals(int x, int y)
        {
            return x % 2 == y % 2;
        }

        public int GetHashCode(int obj)
        {
            return obj % 2;
        }
    }

    static void Main(string[] args)
    {
        var x = new int[] { 1, 2, 3, 4 }.Distinct(new IntParitiyComparer());

        foreach (var y in x) Console.WriteLine(y);
    }

It's clumsy; DistinctBy would be cleaner.

Jay Bazuzi