Lieven Cardoen
Lieven Cardoen

Reputation: 25959

Linq Distinct based on property of object

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>

Upvotes: 8

Views: 6769

Answers (4)

Jay Bazuzi
Jay Bazuzi

Reputation: 46506

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.

Upvotes: 2

jason
jason

Reputation: 241641

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

Upvotes: 5

Mark Seemann
Mark Seemann

Reputation: 233150

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.

Upvotes: 6

Mark Byers
Mark Byers

Reputation: 838186

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.

Upvotes: 2

Related Questions