I am playing with LINQ to learn about it, but I can\'t figure out how to use Distinct
when I do not have a simple list (a simple list of integers is pretty easy
If you don't want to add the MoreLinq library to your project just to get the DistinctBy
functionality then you can get the same end result using the overload of Linq's Distinct
method that takes in an IEqualityComparer
argument.
You begin by creating a generic custom equality comparer class that uses lambda syntax to perform custom comparison of two instances of a generic class:
public class CustomEqualityComparer : IEqualityComparer
{
Func _comparison;
Func _hashCodeFactory;
public CustomEqualityComparer(Func comparison, Func hashCodeFactory)
{
_comparison = comparison;
_hashCodeFactory = hashCodeFactory;
}
public bool Equals(T x, T y)
{
return _comparison(x, y);
}
public int GetHashCode(T obj)
{
return _hashCodeFactory(obj);
}
}
Then in your main code you use it like so:
Func areEqual = (p1, p2) => int.Equals(p1.Id, p2.Id);
Func getHashCode = (p) => p.Id.GetHashCode();
var query = people.Distinct(new CustomEqualityComparer(areEqual, getHashCode));
Voila! :)
The above assumes the following:
Person.Id
is of type int
people
collection does not contain any null elementsIf the collection could contain nulls then simply rewrite the lambdas to check for null, e.g.:
Func areEqual = (p1, p2) =>
{
return (p1 != null && p2 != null) ? int.Equals(p1.Id, p2.Id) : false;
};
EDIT
This approach is similar to the one in Vladimir Nesterovsky's answer but simpler.
It is also similar to the one in Joel's answer but allows for complex comparison logic involving multiple properties.
However, if your objects can only ever differ by Id
then another user gave the correct answer that all you need to do is override the default implementations of GetHashCode()
and Equals()
in your Person
class and then just use the out-of-the-box Distinct()
method of Linq to filter out any duplicates.