2

We have a collection of objects with a count property as follows...

Item A : Count 4
Item B : Count 2
Item C : Count 5 <-- We want this one
Item D : Count 3

(Note the actual list can have hundreds of items.)

We're trying to write a LINQ statement that returns 'Item C' since it has the highest value for Count.

Note: We don't want the count. We want the item with the highest count.

Of course this can be easily done with simple looping constructs, but I'm wondering if it can be achieved purely with LINQ.

Only thing I can think of is to use the Aggregate statement like this...

var item = Screen.Items
            .Aggregate( (highestItem, nextItem) => 
                highestItem = (highestItem == null)
                    ? nextItem
                    : (highestItem.Count < nextItem.Count)
                        ? nextItem
                        : highestItem);

Seems verbose though. Is there a different, shorter way?

Mark A. Donohoe
  • 28,442
  • 25
  • 137
  • 286
  • 2
    http://stackoverflow.com/questions/1101841/linq-how-to-perform-max-on-a-property-of-all-objects-in-a-collection-and-ret – Khanh TO Jul 26 '15 at 04:54

2 Answers2

2

You can use the default Max() LINQ extensions if you just need the Count value (I assume pairs is ICollection<KeyValuePair<Item, int>>).

var highestCount = pairs.Max(pair => pair.Value);

Or you can add MoreLINQ nuget and use MaxBy() extension to get Item:

var itemWithHighestCount = pairs.MaxBy(pair => pair.Value).Key;

UPDATE:

Just wanted to share some performance results. For a List<object, long> collection with 10 million elements and random long values (average time for 10 runs):

  • Aggregate takes 430 ms
  • OrderBy takes 5,991 ms
  • MaxBy from MoreLINQ takes 231 ms
Nikolai Samteladze
  • 7,699
  • 6
  • 44
  • 70
  • MoreLINQ is an add-on? What about built-in LINQ functions? Only thing I can think of is .Aggregate like I showed above. – Mark A. Donohoe Jul 26 '15 at 05:14
  • moreLINQ is a library you'd have to include in your program. It's not part of .NET Framework. There is nothing like this built in. You could either use your `Aggregate` solution or use `OrderByDescending(x => x.Value).First();` – MarcinJuraszek Jul 26 '15 at 05:16
  • Yeah, MoreLINQ is a nuget that our will need to add (or you can add it as DLL). If you don't want to use it that `OrdeyBy()` is probably your best solution. It will be faster than `Aggregate()` and more readable. – Nikolai Samteladze Jul 26 '15 at 05:20
  • @NikolaiSamteladze I wouldn't expect `OrderBy` to be faster, because `Aggregate` can be done in *O(n)* time, and sorting required at least *O(n*log(n))` – MarcinJuraszek Jul 26 '15 at 05:25
  • I was just thinking the same thing (r.e. Aggregate vs. OrderBy.) Doesn't the Aggregate loop over the list one time whereas OrderBy has to do it several times? – Mark A. Donohoe Jul 26 '15 at 05:32
  • You are right. `OrderBy` would be much slower. I does much more than just finding the maximum. – Nikolai Samteladze Jul 26 '15 at 05:39
  • Timed it actually. On `List` with 10 million elements `OrderBy` takes 5991 ms on average, `Aggregate` takes 430 ms and `MoreLINQ` takes 231 ms. – Nikolai Samteladze Jul 26 '15 at 05:41
0

Microsoft's Reactive Framework team wrote some very nice LINQ extensions. Do a NuGet for "Ix-Main" (stands for "Interactive Extensions") and you can then do this:

var item = list.MaxBy(i => i.Count);
Enigmativity
  • 113,464
  • 11
  • 89
  • 172