LINQ的 - 各组前值(Linq - Top value from each group)

2019-08-18 20:30发布

我如何使用LINQ到从每个组中选择最值

当我有一个代码段,如:

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}
 };

期望的结果:


Team Name         Player Name     Score

Srilanka          Jayasurya        433

England           colingwood       421

Australia         Clark            334 

Answer 1:

我的答案是类似尤里的,但使用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);
}

请注意,我从“团队”,以“玩家”,因为我相信它更有意义改变了类型的名字 - 你不与球队集合开始,你的队员集合出发。



Answer 2:

以下代码获取所需的值:

foreach (Team team in teams
    .GroupBy(t => t.TeamName)
    .Select(ig => ig.MaxValue(t => t.PlayerScore)))
{
    Console.WriteLine(team.TeamName + " " + 
        team.PlayerName + " " + 
        team.PlayerScore);
}

它需要以下扩展名,我今天早些时候写道:

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;
    }
}

下面获取不带扩展名的答案,但稍微慢一点:

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);
}


Answer 3:

这将要求你按团队名称,然后选择最高分。

唯一棘手的部分是获得相应的播放器,但它不是太糟糕了。 只需选择与最高分球员。 粗的,如果它的可能的一个以上的玩家,以如下所示,而不是单()函数具有相同的分数不使用First()函数此。

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
    };

仅供参考 - 我没跑对你的数据的代码,它的工作(后我固定一个,小的数据错误)。



Answer 4:

我会用这个Lambda表达式:

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


Answer 5:

通过该跛脚鸭提出的实现是伟大的,但需要两个O(N)经过分组集找出最大。 这将有利于从一次计算MaxScore,然后再利用。 这是的SelectMany(C#中的let关键字)就派上用场了。 下面是优化查询:

var x = from t in teams 
        group t by t.TeamName into groupedT 
        let maxScore = groupedT.Max(gt => gt.PlayerScore)
        select new 
        { 
           TeamName = groupedT.Key,
           MaxScore = maxScore, 
           MaxPlayer = groupedT.First(gt2 => gt2.PlayerScore == maxScore).PlayerName 
        };


Answer 6:

我建议你首先实现对所谓的顶部例如,IEnumerbale类的扩展方法:

IEnumerable<T,T1> Top(this IEnumerable<T> target, Func<T1> keySelector, int topCount)
{
    return target.OrderBy(i => keySelector(i)).Take(topCount);
}

然后,你可以这样写:

teams.GroupBy(团队=> team.TeamName)赛拓朴(团队=> team.PlayerScore,1)。

可能有一些轻微的修改,使其编译。



文章来源: Linq - Top value from each group
标签: c# linq lambda