Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Distinct Linq filtering with additional criteria

Tags:

c#

linq

distinct

I have a list which contains duplicate item values (by ID), but with a different (or possibly equal) priority. Duplicate items with same or lower priority should be removed from the list.

For example:

var items = new {
   new { Id=2, Priority=3 },
   new { Id=4, Priority=4 },
   new { Id=1, Priority=4 },
   new { Id=2, Priority=5 },
   new { Id=4, Priority=4 }
};

RemoveDuplicates(items);

// items should now contain distinct values,
// with highest possible priority
var items = new {
   new { Id=1, Priority=4 }, // this one was unique
   new { Id=2, Priority=5 }, // this one was duplicate with higher priority
   new { Id=4, Priority=4 }, // this one was duplicate with same priority
};

Is it possible to do this using LINQ? I know I could sort the list by ID and then check adjacent items, but just wanted to check if this is possible.

(update: input values are not necessarily grouped by IDs)

like image 313
linq-question Avatar asked Jun 30 '11 08:06

linq-question


People also ask

Why distinct is not working in Linq?

LINQ Distinct is not that smart when it comes to custom objects. All it does is look at your list and see that it has two different objects (it doesn't care that they have the same values for the member fields). One workaround is to implement the IEquatable interface as shown here.

How to Distinct Using LINQ?

If you want to return distinct elements from sequences of objects of some custom data type, you have to implement the IEquatable<T> generic interface in the class. The following code example shows how to implement this interface in a custom data type and provide GetHashCode and Equals methods.


2 Answers

        var items = new[] {
           new { Id=2, Priority=3 },
           new { Id=2, Priority=5 },
           new { Id=1, Priority=4 },
           new { Id=4, Priority=4 },
           new { Id=4, Priority=4 }
        };

        var deduped = items
            .GroupBy(item => item.Id)
            .Select(group => group.OrderByDescending(item => item.Priority).First())
            .OrderBy(item => item.Id);
like image 137
Petar Ivanov Avatar answered Sep 30 '22 16:09

Petar Ivanov


The Distinct Extension Method returns the distinct elements from a sequence. You can provide an IEqualityComparer<TSource> to determine when two elements are equal. However, the method does not allow you to choose which of the two equal elements is used.

You can use the GroupBy Extension Method to group the list by ID and then select the element with the highest priority from each group:

var query = items.GroupBy(item => item.Id)
                 .Select(g => g.MaxBy(item => item.Priority))
                 .OrderBy(item => item.Id);

using MaxBy from MoreLINQ.

like image 41
dtb Avatar answered Sep 30 '22 17:09

dtb