I have a situation in which I have a list of objects with an int property and I need to retrieve the 3 objects with the highest value for that property. The MoreLinq MaxBy function is very convenient to find the single highest, but is there a way I can use that to find the 3 highest? (Not necessarily of the same value). The implementation I'm currently using is to find the single highest with MaxBy, remove that object from the list and call MaxBy again, etc. and then add the objects back into the list once I've found the 3 highest. Just thinking about this implementation makes me cringe and I'd really like to find a better way.
Asked
Active
Viewed 2,995 times
2 Answers
2
Update: In version 3, MaxBy
(including MinBy
) of MoreLINQ was changed to return a sequence as opposed to a single item.
Use MoreLINQ's PartialSort
or PartialSortBy
. The example below uses PartialSortBy
to find and print the longest 5 words in a given text:
var text = @"
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Etiam gravida nec mauris vitae sollicitudin. Suspendisse
malesuada urna eu mi suscipit fringilla. Donec ut ipsum
aliquet, tincidunt mi sed, efficitur magna. Nulla sit
amet congue diam, at posuere lectus. Praesent sit amet
libero vehicula dui commodo gravida eget a nisi. Sed
imperdiet arcu eget erat feugiat gravida id non est.
Nam malesuada nibh sit amet nisl sollicitudin vestibulum.";
var words = Regex.Matches(text, @"\w+");
var top =
from g in words.Cast<Match>()
.Select(m => m.Value)
.GroupBy(s => s.Length)
.PartialSortBy(5, m => m.Key, OrderByDirection.Descending)
select g.Key + ": " + g.Distinct().ToDelimitedString(", ");
foreach (var e in top)
Console.WriteLine(e);
It will print:
14: malesuadafsfjs 12: sollicitudin 11: consectetur, Suspendisse 10: adipiscing, vestibulum 9: malesuada, fringilla, tincidunt, efficitur, imperdiet

Atif Aziz
- 36,108
- 16
- 64
- 74
1
in this case, you could simply do
yourResult.OrderByDescending(m => m.YourIntProperty)
.Take(3);
Now, this will retrieve you 3 objects.
So if you've got 4 objects sharing the same value (which is the max), 1 will be skipped. Not sure if that's what you want, or if it's not a problem...
But MaxBy
will also retrieve only one element if you have many elements with the same "max value".

Raphaël Althaus
- 59,727
- 6
- 96
- 122
-
What is "yourResult" in this case? Is that after I've used MaxBy or is that an entirely different implementation? – Fenoec Oct 03 '13 at 15:53
-
well, it's your `IEnumerable
` (your list of objects). I would just use `OrderByDescending(bla bla)` instead of `MaxBy` – Raphaël Althaus Oct 03 '13 at 15:55 -
I was making that a lot more complex than it needed to be ;) Thanks for the solution, works perfectly. – Fenoec Oct 03 '13 at 15:59
-
This works, but it is not as efficient as the answer by @Atif Aziz, since it fully sorts the list, whereas PartialSort does less work. – Hugh W Oct 29 '22 at 15:42