按组进行分组,然后对每个组的结果进行聚合。

3

我对LINQ to objects中的groupby行为感到困惑。假设我有以下类:

public class person
{
   public string name { get; set; }
   public int age { get; set; }
}

假设我有一个人的列表person;List<person> people 现在,我想生成一个 IEnumerable<T>,其具有一个 IGrouping 或匿名类型,该类型有两个属性:1) 名称(键)和 2) 具有该名称的人所有年龄的总和。
这里是我尝试过但不成功的一些示例;
people.GroupBy(x => x.name, x => x, (key, value) => value.Aggregate((c, n) => c + n));

这段代码编译时会出现错误:无法将类型 "int" 转换为 "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>,其中T的类型将是x的类型。当然,如果是这种情况,我的第二个示例将完美运行。我的问题有点开放式,但是有人能解释两件事吗?首先; 如何使用LINQ完成我的最终目标?其次,为什么GroupBy的结果不更接近我在这里描述的内容?它是什么?我觉得一个键值对,其中值是与该键匹配的对象集合,比实际返回的更直观。

2个回答

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

如果您愿意,可以再次按名称对结果进行分组,这将是一个以名称为键、年龄为值的分组。


所以我点赞了,因为那满足了我的理论例子,但是如果我实际上必须使用Aggregate来达到我想要的结果怎么办?假设类型更复杂,我不能只提供一个简单的投影来进行求和(需要处理对象上的多个属性等更专有的内容)。 - evanmcdonnal
我认为问题在于你缺少聚合的返回类型。由于你没有指定它,它期望你的结果是 person 类型。两边需要匹配。现在根据你想要返回什么以及涉及到哪些其他类/程序集,你可能无法在使用 ToList() 解决查询之前进行聚合。我在上面添加了这个代码; Result = g.Aggregate(new Int32(), (current, next) => next.age + next.age)。 - Honorable Chow
使用Aggregate的方法并不完全奏效,尽管它更接近我所寻找的东西。例如,如果你只有一个元素,它会返回age * 2,但实际上应该返回age * 1。我认为它对于其他情况可能有效,但我还不确定。 - evanmcdonnal
1
那个聚合函数的使用实际上是不正确的。它并没有给出年龄总和。我需要使用聚合函数,因为我的数据模型比我的示例更复杂。我不能只调用 Sum(x => x.SingleProperty)。我可以编辑示例以更好地演示我实际正在执行的操作,但我认为这并不重要。next.age + next.age 这是不正确的,从我在调试器中看到的情况来看,我相信 currentnew Int32() 的返回值,这会阻止它实际产生正确的结果。 - evanmcdonnal
1
“g”参数从哪里来?在你的示例中没有定义。 - Paul Chernoch
显示剩余3条评论

0

你可以使用表达式语法来完成它

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接