GroupBy 然后对每个组的结果进行聚合

Posted

技术标签:

【中文标题】GroupBy 然后对每个组的结果进行聚合【英文标题】:GroupBy then do aggregation on results for each group 【发布时间】:2014-04-17 21:09:38 【问题描述】:

我对 LINQ to 对象中的 groupby 行为感到困惑。让我们假设我有以下课程;

public class person

   public string name  get; set; 
   public int age  get; set; 

假设我有一个列表或类型的人; List<person> people

现在,我想生成一个具有 IGrouping 或匿名类型的 IEnumerable<T>,它具有两个属性:1) 名称(键)和 2) 具有该名称的人的所有年龄的总和。

这是我尝试过的几个例子(不成功);

people.GroupBy(x => x.name, x => x, (key, value) => value.Aggregate((c, n) => c + n));

编译时会出现错误cannot convert type "int" to "namespace.person"

在此之前,我正在尝试更多类似的东西;

people.GroupBy(x => x.name).Select(g => new  g.Key, g.Aggregate((c, n) => c + n))  );

这基本上给出了相同的错误。我基本上很难理解GroupBy 返回的值到底是什么。起初,我认为基本重载给了我一个键值对,其中 x.Key 是我用我的委托指定的键,x.Value 将是 IEnumerable<T> 其中 typeof T 将是 x 的类型.当然,如果是这样的话,我的第二个例子会很有效。我的问题有点开放式,但有人可以首先解释两件事;如何使用 LINQ 实现我的最终目标?其次,为什么GroupBy 的结果不像我在这里描述的那样?它是什么?我觉得像一个键值对,其中的值是与该键匹配的对象的集合,比实际返回的要直观得多。

【问题讨论】:

【参考方案1】:
 var grouped = people.GroupBy(x => x.name)
                                .Select(x => new
                                    
                                        Name = x.Key,
                                        Age = x.Sum(v => v.age),
                                        Result = g.Aggregate(new Int32(), (current, next) => next.age + next.age)
                                    );

如果您愿意,您可以再次按名称对结果进行分组,它将是以 Key 为名称,Age 为值的分组

【讨论】:

所以我投了赞成票,因为这满足了我的理论示例,但是如果我实际上必须使用 Aggregate 来实现我正在寻找的结果呢?假设类型更复杂,我不能只提供一个简单的预测来求和(需要更专有的东西来处理对象上的多个属性)。 我认为问题是您缺少聚合的返回类型。由于您没有指定它,因此它期望您的结果是 person 类型。双方需要配合。现在,根据您要返回的内容以及涉及的其他类/程序集,您可能无法进行聚合,直到您使用 ToList() 解决了查询。我在上面添加了这个;结果 = g.Aggregate(new Int32(), (current, next) => next.age + next.age) 虽然它更接近我正在寻找的东西,但 Aggregate 的使用并不是很有效。例如,如果您有一个元素,它将返回age * 2,而它应该只返回age * 1。我认为它适用于其他情况,尽管我还不确定。 聚合的使用实际上并不正确。它没有给你年龄的总和。我需要使用聚合,因为我的数据模型比我的示例更复杂。我不能只打电话给Sum(x => x.SingleProperty)。我可以编辑该示例以使其更好地演示我实际正在执行的操作,但我认为这并不重要。next.age + next.age 这是不对的,从我在调试器中看到的内容来看,我相信current 指的是new Int32() 的返回值会阻止它实际产生正确的结果。 “g”参数从何而来?您的示例中没有定义它。【参考方案2】:

你可以用表达式语法来做到这一点

var results = from p in persons
              group p.car by p.name into g
              select new  name = g.Key, age = g.Sum(c=>.age ;

【讨论】:

以上是关于GroupBy 然后对每个组的结果进行聚合的主要内容,如果未能解决你的问题,请参考以下文章

pandas分组与聚合

分析函数和开窗函数

分析函数之开窗函数over

over(partition by)开窗函数的使用

第十三章 分组数据

Elasticsearch 分组聚合查询(bucket) --- 2022-04-03