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>开发者_JAVA百科;
instead of List<MyClass>
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.
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
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.
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.
精彩评论