Linq - 每组的最高价值

use*_*560 38 c# linq lambda

如何使用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,但使用的MaxByMoreLINQ,它不需要通过整数进行比较:

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)

  • 感谢您展示`OrderBy`方式.我讨厌不必要的扩展. (4认同)

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)

仅供参考 - 我确实对你的数据运行了这个代码并且它有效(在我修复了那个,很少数据错误之后).


chr*_*tle 7

我会使用这个Lambda表达式:

IEnumerable<Team> topsScores = 
teams.GroupBy(x => x.TeamName).Select(t => t.OrderByDescending(c => c.PlayerScore).FirstOrDefault());
Run Code Online (Sandbox Code Playgroud)