GroupBy中最高编号的键

时间:2019-03-03 12:54:05

标签: c# linq

我有一个简单的课:

class Balls
{
    public int BallType;  
}

我有一个非常简单的列表:

var balls = new List<Balls>() 
{ 
    new Balls() { BallType = 1},
    new Balls() { BallType = 1},
    new Balls() { BallType = 1},
    new Balls() { BallType = 2}
};

我在此列表上使用过GroupBy,我想找回拥有最高计数/金额的钥匙:
使用x.GroupBy(q => q.BallType)之后,我尝试使用.Max(),但是它返回3,我需要的密钥是1。

我也尝试使用Console.WriteLine(x.GroupBy(q => q.Balltype).Max().Key);,但是它抛出了System.ArgumentException

2 个答案:

答案 0 :(得分:1)

这是我想出的:

var mostCommonBallType = balls
    .GroupBy(k => k.BallType)
    .OrderBy(g => g.Count())
    .Last().Key

您按BallType分组,按组中的项目数排序,获取最后一个值(因为order by按升序排列,最常见的值为最后一个),然后返回它的键值

答案 1 :(得分:1)

有人提出了对序列进行排序的想法:

var mostCommonBallType = balls
.GroupBy(k => k.BallType)
.OrderBy(g => g.Count())
.Last().Key

除此以外,OrderByDescending并使用FirstOrDefault效率更高,如果您的Balls集合为空,也会遇到麻烦。

如果您使用不同的GroupBy重载,则不会出现这些问题

var mostCommonBallType = balls.GroupBy(
    // KeySelector:
    k => k.BallType,

    // ResultSelector:
    (ballType, ballsWithThisBallType) => new
    {
        BallType = ballType,
        Count = ballsWithThisBallType.Count(),
    })
    .OrderByDescending(group => group.Count)
    .Select(group => group.BallType)
    .FirstOrDefault();

这解决了前面提到的问题。但是,如果只需要第一个元素,为什么要订购第二个和第三个元素呢?使用Aggregate代替OrderByDescending将仅枚举一次:

假设您的收藏集不为空:

var result = ... GroupBy(...)
    .Aggregate( (groupWithHighestBallCount, nextGroup) =>
         (groupWithHighestBallCount.Count >= nextGroup.Count) ?
             groupWithHighestBallCount : nextGroup)
    .Select(...).FirstOrDefault();

Aggregate接受非空序列的第一个元素,并将其分配给groupWithHighestBallCount。然后遍历序列的其余部分,并将此nextGroup.Count与groupWithHighestBallCount.Count进行比较。它将具有最高值的一个作为下一个groupWithHighestBallCount。返回值是最终的groupWithHighestBallCount。

看到聚合只枚举一次吗?