如何使用Linq从每个组中选择Top值
当我有一个代码段,如:
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}
};
Run Code Online (Sandbox Code Playgroud)
期望的结果:
Team Name Player Name Score Srilanka Jayasurya 433 England colingwood 421 Australia Clark 334
Jon*_*eet 28
我的答案类似于Yuriy,但使用的MaxBy是MoreLINQ,它不需要通过整数进行比较:
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);
}
Run Code Online (Sandbox Code Playgroud)
请注意,我已经将类型名称从"团队"更改为"玩家",因为我认为它更有意义 - 您不是从一组团队开始,而是从一组玩家开始.
Yur*_*ich 26
以下代码获取所需的值:
foreach (Team team in teams
.GroupBy(t => t.TeamName)
.Select(ig => ig.MaxValue(t => t.PlayerScore)))
{
Console.WriteLine(team.TeamName + " " +
team.PlayerName + " " +
team.PlayerScore);
}
Run Code Online (Sandbox Code Playgroud)
它需要我今天早些时候写的以下扩展:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
以下是没有扩展名的答案,但稍微慢一点:
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);
}
Run Code Online (Sandbox Code Playgroud)
Mic*_*oie 13
这将要求您按团队名称分组,然后选择最高分数.
唯一棘手的部分是获得相应的玩家,但它并不太糟糕.只需选择具有最高分数的玩家.粗略的,如果多个玩家可能有相同的分数,可以使用如下所示的First()函数而不是Single()函数.
var x =
from t in teams
group t by t.TeamName into groupedT
select new
{
TeamName = groupedT.Key,
MaxScore = groupedT.Max(gt => gt.PlayerScore),
MaxPlayer = groupedT.First(gt2 => gt2.PlayerScore ==
groupedT.Max(gt => gt.PlayerScore)).PlayerName
};
Run Code Online (Sandbox Code Playgroud)
仅供参考 - 我确实对你的数据运行了这个代码并且它有效(在我修复了那个,很少数据错误之后).
我会使用这个Lambda表达式:
IEnumerable<Team> topsScores =
teams.GroupBy(x => x.TeamName).Select(t => t.OrderByDescending(c => c.PlayerScore).FirstOrDefault());
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
25453 次 |
| 最近记录: |