千家信息网

如何利用LINQ进行分组统计

发表于:2025-11-13 作者:千家信息网编辑
千家信息网最后更新 2025年11月13日,这篇文章将为大家详细讲解有关如何利用LINQ进行分组统计,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。让我们来生成要统计的数据,如下所示:IEnumerable>
千家信息网最后更新 2025年11月13日如何利用LINQ进行分组统计

这篇文章将为大家详细讲解有关如何利用LINQ进行分组统计,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

让我们来生成要统计的数据,如下所示:

IEnumerable> GetTuples(int n)  {    var tuples = new Tuple[n];    var rand = new Random();    for (int k = 1, i = 0; i < n; i++)    {      var r = rand.Next(n);      k += (r >= n - 3) ? 2 : ((r >= n - 9) ? 1 : 0);      tuples[i] = new Tuple(k, rand.NextDouble());    }    return tuples;  }

该方法生成 n 项已经排好序的数据。

现在,让我们来按关键字分组,并统计每组的个数和平均值。

首先,使用 C# 的 foreach 循环,如下所示:

IEnumerable> ForEach(IEnumerable> tuples)  {    var result = new List>();    var count = 0;    var sum = 0.0;    int? key = null;    foreach (var v in tuples)    {      if (key != v.Item1)      {        if (key != null) result.Add(new Tuple(key.Value, count, sum / count));        sum = count = 0;        key = v.Item1;      }      count++;      sum += v.Item2;    }    if (key != null) result.Add(new Tuple(key.Value, count, sum / count));    return result;  }

这种方法有个***的缺点就是在 foreach 循环结束之后还要进行一次统计,闻到了代码的"坏味道"。

那么,就让我们来重构吧,这次,使用迭代器进行循环:

IEnumerable> Iterate(IEnumerable> tuples)  {    var result = new List>();    var count = 0;    var sum = 0.0;    int? key = null;    for (var iter = tuples.GetEnumerator(); ; count++, sum += iter.Current.Item2)    {      var hasValue = iter.MoveNext();      if (!hasValue || key != iter.Current.Item1)      {        if (key != null) result.Add(new Tuple(key.Value, count, sum / count));        if (!hasValue) break;        sum = count = 0;        key = iter.Current.Item1;      }    }    return result;  }

这样,就消灭了"坏味道"。

注意,以上两种方法都假设输入数据已经排好序。如若不然,就要先对输入数据进行一次排序。

***,如果使用LINQ的话,还可以更简单:

IEnumerable> Linq(IEnumerable> tuples)  {    var result = new List>();    var q = from k in tuples group k by k.Item1;    foreach (var g in q) result.Add(new Tuple(g.Key, g.Count(), g.Average(v => v.Item2)));    return result;  }

要注意LINQ 方法无论是运行时间还是占用的内存都更大。

我们来看看 Main 方法:

static void Main(string[] args)  {    try    {      new Program().Run(Console.Out, int.Parse(args[0]));    }    catch (Exception ex)    {      Console.WriteLine(ex);    }  }   void Run(TextWriter writer, int n)  {    var tuples = GetTuples(n * 1024 * 1024);    Write("ForEach", writer, ForEach(tuples));    Write("Iterate", writer, Iterate(tuples));    Write(" Linq  ", writer, Linq(tuples));  }

其中的 Write 方法如下所示:

void Write(string title, TextWriter writer, IEnumerable> tuples)  {    writer.WriteLine("==========> " + title + " <============");    writer.WriteLine("Key ------Count Average----------");    var count = 0;    var sum = 0.0;    foreach (var t in tuples)    {      writer.WriteLine("{0,3} {1,11:N0} {2}", t.Item1, t.Item2, t.Item3);      count += t.Item2;      sum += t.Item2 * t.Item3;    }    writer.WriteLine("--- ----------- -----------------");    writer.WriteLine("{0,3} {1,11:N0} {2}", tuples.Count(), count, sum / count);    writer.WriteLine();  }

***,这个程序的输出如下所示:

==========> ForEach <============
Key ------Count Average----------
1 10,476 0.492122426354162
2 1,633,289 0.499917991099794
3 981,345 0.500446307804579
5 1,542,377 0.500567888024527
6 478,158 0.499376479287702
8 62,325 0.501552373474687
9 1,463,104 0.500270067230854
11 802,680 0.500518684820775
13 367,798 0.499572390413821
14 492,947 0.500767958524
16 2,403,053 0.500023199420802
17 248,208 0.499988049057847
--- ----------- -----------------
12 10,485,760 0.50018897689056

==========> Iterate <============
Key ------Count Average----------
1 10,476 0.492122426354162
2 1,633,289 0.499917991099794
3 981,345 0.500446307804579
5 1,542,377 0.500567888024527
6 478,158 0.499376479287702
8 62,325 0.501552373474687
9 1,463,104 0.500270067230854
11 802,680 0.500518684820775
13 367,798 0.499572390413821
14 492,947 0.500767958524
16 2,403,053 0.500023199420802
17 248,208 0.499988049057847
--- ----------- -----------------
12 10,485,760 0.50018897689056

==========> Linq <============
Key ------Count Average----------
1 10,476 0.492122426354162
2 1,633,289 0.499917991099794
3 981,345 0.500446307804579
5 1,542,377 0.500567888024527
6 478,158 0.499376479287702
8 62,325 0.501552373474687
9 1,463,104 0.500270067230854
11 802,680 0.500518684820775
13 367,798 0.499572390413821
14 492,947 0.500767958524
16 2,403,053 0.500023199420802
17 248,208 0.499988049057847
--- ----------- -----------------
12 10,485,760 0.50018897689056


这个程序中用到的 Tuple 类如下所示:

class Tuple {    public T1 Item1 { get; private set; }    public T2 Item2 { get; private set; }    public Tuple(T1 item1, T2 item2) { Item1 = item1; Item2 = item2; }  }   class Tuple : Tuple {    public T3 Item3 { get; private set; }    public Tuple(T1 item1, T2 item2, T3 item3) : base(item1, item2) { Item3 = item3;  }  }

其实 .NET Framework 4.0 Base Class Library 中已经有 Tuple 类了。

关于"如何利用LINQ进行分组统计"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

方法 统计 数据 分组 篇文章 循环 味道 更多 程序 生成 输入 不错 实用 如若不然 个数 中用 代码 关键 关键字 内存 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 计算机网络安全和防御技术 长宁区品牌软件开发口碑推荐 路由器到服务器延迟17 嘉兴电脑软件开发是做什么的 固威达软件开发怎么样 沈阳华鼎软件开发有限公司 广州市软件开发公司哪家可靠 中国核心期刊数据库什么意思 湖北网络安全审计硬件稳定性 成都web前端软件开发服务 苏30为什么用f16服务器 教育网网络安全漏洞 服务器安全连是什么接 数据库查部门人数 清科数据库技术路线图 数据库数据主键扩增问题 网络安全运营技术试卷 含软件开发的专业 讯鸿网络技术有限公司官网 网络安全有关班会主题 部落冲突迁移小米服务器 .net如何查找数据库 网络安全宣传周活动策划 三级网络技术分笔试和上级 莆田市盛品阁网络技术有限公司 静安区特殊软件开发技术指导 毕业论文数据库表格 校园网络安全小报三年 嵌入式软件开发服务增值税 讯鸿网络技术有限公司官网
0