Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get the top three players and their high scores from a collection using linq and lambdas

Tags:

c#

lambda

linq

I have the following collection of scores;

var scores = new[]
    {
      new { score = 10, player = "Dave" }, 
      new { score = 9, player = "Dave" }, 
      new { score = 8, player = "Steve" }, 
      new { score = 7, player = "Pete" }, 
      new { score = 8, player = "Paul" }, 
      new { score = 4, player = "Mike" }
    };

I would like the a collection of scores containing the top 3 players and their high scores (ordered by score, highest score first) i.e.

{ score = 10, player = "Dave" }
{ score = 8, player = "Paul" }
{ score = 8, player = "Steve" }

This won't work;

var top3 = scores.OrderByDescending(s => s.score).Take(3);

This is because Dave has two of the top three scores and would appear twice.

Paul and Steve have the same score, for the purposes of this question I do not care which appears first in the list but there is a bonus up-vote for any solution that puts the person whose name appears first in the alphabet highest in the event that their scores are tied (to return results in the exact order shown in my example results).

The answer should use linq and lambda expressions

Thanks

like image 463
mark_h Avatar asked Dec 13 '25 08:12

mark_h


2 Answers

If a player name should only appear once you have to group the collection by player and order each group by score. Then you can pick the highest 3.

var top3 = scores.GroupBy(x => x.player)
                 .Select(x => x.OrderByDescending(y => y.score).First())
                 .OrderByDescending(x => x.score)
                 .ThenBy(x => x.player)
                 .Take(3);
like image 162
fubo Avatar answered Dec 15 '25 03:12

fubo


You can group them and then pick the maximum score of each player, and then order them:

var top3 = scores.GroupBy(x=>x.player)
                 .Select(g=>new 
                         {
                           player=g.Key,
                           score=g.Max(p=>p.score)
                        })
                 .OrderByDescending(s => s.score)
                 .ThenBy(p=>p.player).Take(3);
like image 20
Ehsan Sajjad Avatar answered Dec 15 '25 01:12

Ehsan Sajjad