How can I employ Linq to select Top value from each group
when I have a code segment like :
var teams = new Team[]
{
new Team{PlayerName="Ricky",TeamName="Australia", PlayerScore=234},
new Team{PlayerName="Hussy",TeamName="Australia", PlayerScore=134},
new Team{PlayerName="Clark",TeamName="Australia", PlayerScore=334},
new Team{PlayerName="Sankakara",TeamName="SriLanka", PlayerScore=34},
new Team{PlayerName="Udana",TeamName="SriLanka", PlayerScore=56},
new Team{PlayerName="Jayasurya",TeamName="SriLanka", PlayerScore=433},
new Team{PlayerName="Flintop",TeamName="England", PlayerScore=111},
new Team{PlayerName="Hamirson",TeamName="England", PlayerScore=13},
new Team{PlayerName="Colingwood",TeamName="England", PlayerScore=421}
};
Desired Result :
Team Name Player Name Score Srilanka Jayasurya 433 England colingwood 421 Australia Clark 334
My answer is similar to Yuriy's, but using MaxBy
from MoreLINQ, which doesn't require the comparison to be done by ints:
var query = from player in players
group player by player.TeamName into team
select team.MaxBy(p => p.PlayerScore);
foreach (Player player in query)
{
Console.WriteLine("{0}: {1} ({2})",
player.TeamName,
player.PlayerName,
player.PlayerScore);
}
Note that I've changed the type name from "Team" to "Player" as I believe it makes more sense - you don't start off with a collection of teams, you start off with a collection of players.
The following code gets the desired value:
foreach (Team team in teams
.GroupBy(t => t.TeamName)
.Select(ig => ig.MaxValue(t => t.PlayerScore)))
{
Console.WriteLine(team.TeamName + " " +
team.PlayerName + " " +
team.PlayerScore);
}
It requires the following extension that I wrote earlier today:
public static T MaxValue<T>(this IEnumerable<T> e, Func<T, int> f)
{
if (e == null) throw new ArgumentException();
using(var en = e.GetEnumerator())
{
if (!en.MoveNext()) throw new ArgumentException();
int max = f(en.Current);
T maxValue = en.Current;
int possible = int.MaxValue;
while (en.MoveNext())
{
possible = f(en.Current);
if (max < possible)
{
max = possible;
maxValue = en.Current;
}
}
return maxValue;
}
}
The following gets the answer without the extension, but is slightly slower:
foreach (Team team in teams
.GroupBy(t => t.TeamName)
.Select(ig => ig.OrderByDescending(t => t.PlayerScore).First()))
{
Console.WriteLine(team.TeamName + " " +
team.PlayerName + " " +
team.PlayerScore);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With