LINQ 与 groupby 和计数

Posted

技术标签:

【中文标题】LINQ 与 groupby 和计数【英文标题】:LINQ with groupby and count 【发布时间】:2011-11-09 06:52:29 【问题描述】:

这很简单,但我不知所措: 鉴于这种类型的数据集:

UserInfo(name, metric, day, other_metric)

还有这个样本数据集:

joe  1 01/01/2011 5
jane 0 01/02/2011 9
john 2 01/03/2011 0
jim  3 01/04/2011 1
jean 1 01/05/2011 3
jill 2 01/06/2011 5
jeb  0 01/07/2011 3
jenn 0 01/08/2011 7

我想检索一个按顺序(0,1,2,3..)列出指标的表格,其中包含计数发生的总次数。所以从这个集合中,你最终会得到:

0 3    
1 2    
2 2    
3 1

我正在努力使用 LINQ 语法,但我被困在放置 groupby 和计数的位置... 有什么帮助吗?

POST 编辑:我永远无法让发布的答案正常工作,因为它们总是返回一条记录,其中包含不同计数的数量。但是,我能够将一个 LINQ to SQL 示例放在一起,该示例确实有效:

var pl = from r in info
         orderby r.metric    
         group r by r.metric into grp
         select new  key = grp.Key, cnt = grp.Count();

此结果为我提供了一组有序的记录,其中包含“指标”以及与每个记录关联的用户数。总的来说,我显然对 LINQ 很陌生,而且在我未经训练的眼中,这种方法似乎与纯 LINQ 方法非常相似,但却给了我不同的答案。

【问题讨论】:

是的,我有,但吉米的解释对我帮助更大。然而,我始终无法让他的榜样发挥作用,但它确实将我引向了一个新的方向。 @Jimmy 使用 LINQ 表达式的函数语法而不是标准的 LINQ 查询语法,此外他决定展示这些函数的立即执行而不是延迟执行格式。对于一个会感到困惑的新人。不知道他为什么这么做。 【参考方案1】:

调用GroupBy 后,您会得到一系列组IEnumerable<Grouping>,其中每个分组本身都会公开用于创建组的Key,并且也是原始数据集中任何项目的IEnumerable<T>。您只需在该分组上调用 Count() 即可获得小计。

foreach(var line in data.GroupBy(info => info.metric)
                        .Select(group => new  
                             Metric = group.Key, 
                             Count = group.Count() 
                        )
                        .OrderBy(x => x.Metric))

     Console.WriteLine("0 1", line.Metric, line.Count);


> 这是一个非常快速的回复,但我在第一行遇到了一些问题,特别是“data.groupby(info=>info.metric)”

我假设您已经有一些 class 的列表/数组,看起来像

class UserInfo 
    string name;
    int metric;
    ..etc..
 
...
List<UserInfo> data = ..... ;

当你做data.GroupBy(x =&gt; x.metric)时,它的意思是“对于data定义的IEnumerable中的每个元素x,计算它是.metric,然后将所有具有相同度量的元素组合成一个Grouping并返回所有结果组的IEnumerable。给定您的示例数据集

    <DATA>           | Grouping Key (x=>x.metric) |
joe  1 01/01/2011 5  | 1
jane 0 01/02/2011 9  | 0
john 2 01/03/2011 0  | 2
jim  3 01/04/2011 1  | 3
jean 1 01/05/2011 3  | 1
jill 2 01/06/2011 5  | 2
jeb  0 01/07/2011 3  | 0
jenn 0 01/08/2011 7  | 0

在groupby之后会产生如下结果:

(Group 1): [joe  1 01/01/2011 5, jean 1 01/05/2011 3]
(Group 0): [jane 0 01/02/2011 9, jeb  0 01/07/2011 3, jenn 0 01/08/2011 7]
(Group 2): [john 2 01/03/2011 0, jill 2 01/06/2011 5]
(Group 3): [jim  3 01/04/2011 1]

【讨论】:

这是一个非常快速的回复,但我在第一行遇到了一些问题,特别是“data.groupby(info=>info.metric)”。显然“数据”是当前数据集,但“info.metric”代表什么?类定义? "info.metric" 将是您在问题中提到的 UserInfo 类的指标属性/字段。 谢谢,但实际上这似乎给了我一个值 - 即不同指标计数的总数。在这个例子中,我得到“metrics 4”,这表明我有多少不同的计数。 哇。你完全解释了分组!仅此一项就值得发帖……我仍然得到“指标 4”的结果,但谢谢! 这个答案的开头,“在调用 GroupBy 之后,你会得到一系列组 IEnumerable,其中每个 Grouping 本身都公开了用于创建组的 Key,并且也是一个 IEnumerable原始数据集中的任何项目”,这是我读过的对 LINQ GroupBy 最清晰的解释,谢谢。【参考方案2】:

假设userInfoListList&lt;UserInfo&gt;

var groups = userInfoList.GroupBy(n => n.metric)
                         .Select(n => new
                          
                               MetricName = n.Key,
                               MetricCount = n.Count()
                          )
                         .OrderBy(n => n.MetricName);

GroupBy()n =&gt; n.metric 的 lambda 函数意味着它将从遇到的每个 UserInfo 对象中获取字段 metricn 的类型取决于上下文,在第一次出现时其类型为 UserInfo,因为列表包含 UserInfo 对象。在第二次出现时,n 的类型为 Grouping,因为现在它是 Grouping 对象的列表。

Groupings 具有扩展方法,例如 .Count().Key() 以及几乎所有您期望的其他方法。就像您在 string 上检查 .Length 一样,您可以在组上检查 .Count()

【讨论】:

【参考方案3】:
userInfos.GroupBy(userInfo => userInfo.metric)
        .OrderBy(group => group.Key)
        .Select(group => Tuple.Create(group.Key, group.Count()));

【讨论】:

以上是关于LINQ 与 groupby 和计数的主要内容,如果未能解决你的问题,请参考以下文章

通过计数与组进行 Linq

Linq 计数错误(列)

左外连接和多重计数 SQL to LINQ

Visual Web Developer 2008 不会从 Linq 自动生成类

LINQ 查询多个组和最新记录的计数 - Oracle DB

使用Linq to Entities在一个请求中选择计数和计数