How to use LINQ Distinct() with multiple fields
The Distinct() guarantees that there are no duplicates pair (CategoryId, CategoryName).
- exactly that
Anonymous types 'magically' implement Equals
and GetHashcode
I assume another error somewhere. Case sensitivity? Mutable classes? Non-comparable fields?
Use the Key
keyword in your select will work, like below.
product.Select(m => new {Key m.CategoryId, Key m.CategoryName}).Distinct();
I realize this is bringing up an old thread but figured it might help some people. I generally code in VB.NET when working with .NET so Key
may translate differently into C#.
This is my solution, it supports keySelectors of different types:
public static IEnumerable<TSource> DistinctBy<TSource>(this IEnumerable<TSource> source, params Func<TSource, object>[] keySelectors)
{
// initialize the table
var seenKeysTable = keySelectors.ToDictionary(x => x, x => new HashSet<object>());
// loop through each element in source
foreach (var element in source)
{
// initialize the flag to true
var flag = true;
// loop through each keySelector a
foreach (var (keySelector, hashSet) in seenKeysTable)
{
// if all conditions are true
flag = flag && hashSet.Add(keySelector(element));
}
// if no duplicate key was added to table, then yield the list element
if (flag)
{
yield return element;
}
}
}
To use it:
list.DistinctBy(d => d.CategoryId, d => d.CategoryName)
I assume that you use distinct like a method call on a list. You need to use the result of the query as datasource for your DropDownList, for example by materializing it via ToList
.
var distinctCategories = product
.Select(m => new {m.CategoryId, m.CategoryName})
.Distinct()
.ToList();
DropDownList1.DataSource = distinctCategories;
DropDownList1.DataTextField = "CategoryName";
DropDownList1.DataValueField = "CategoryId";
Another way if you need the real objects instead of the anonymous type with only few properties is to use GroupBy
with an anonymous type:
List<Product> distinctProductList = product
.GroupBy(m => new {m.CategoryId, m.CategoryName})
.Select(group => group.First()) // instead of First you can also apply your logic here what you want to take, for example an OrderBy
.ToList();
A third option is to use MoreLinq's DistinctBy
.