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.
To get unique elements. List<int> myList = list. Distinct(). ToList();
Returns a list that contains all the values in list list with duplicates removed.
C# Linq Distinct() method removes the duplicate elements from a sequence (list) and returns the distinct elements from a single data source. It comes under the Set operators' category in LINQ query operators, and the method works the same way as the DISTINCT directive in Structured Query Language (SQL).
The Distinct function evaluates a formula across each record of a table and returns a one-column table of the results with duplicate values removed. The name of the column is Result. Fields of the record currently being processed are available within the formula.
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);
You can use the Distinct() overload that accepts an IEqualityComparer argument.
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()));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With