C#进阶-LINQ表达式之GroupBy分组查询

简介: 本篇文章我们将演示LINQ扩展包基础语法里的GroupBy分组查询,并实现投影等实际操作中常用的类型转换手法。目前LINQ支持两种语法,我会在每个案例前先用大家熟知的SQL语句表达,再在后面用C#的两种LINQ语法分别实现。LINQ语法第一次接触难免感到陌生,最好的学习方式就是在项目中多去使用,相信会有很多感悟。

分组查询

在学习之前,我们要做一些准备工作,我们需要创建User对象和包含User对象的集合,作为后面查询和输出的数据源,参见这篇文章C#进阶之LINQ表达式总结完成准备工作。

数据源:


1、单属性分组查询全部信息

这里我们举一个最简单的例子,根据职业分组,获得每组的集合:

/* C#版本1 */IEnumerable<IGrouping<string, User>>UserGroupByOccupation=list.GroupBy(s=>s.occupation);
/* C#版本2 */IEnumerable<IGrouping<string, User>>UserGroupByOccupation=fromuinlistgroupubyu.occupationintonselectn;
/* C#版本3 *///这里的版本3是版本2的衍生版本,用自定义对象类ListGroupResult替代 IGrouping<string, User>classListGroupResult{
publicstringKey { get; set; }
publicList<User>UserList { get; set; }
}
IIEnumerable<ListGroupResult>UserGroupByOccupation=fromuinlistgroupubyu.occupationintonselectnewListGroupResult()
                  {
Key=n.Key,  //这个Key是occupationUserList=n.ToList()
                  };

根据Occupation分为四组:




/* 遍历 输出 *//*适用于C#版本1 和2*/foreach(IGrouping<string, User>uinUserGroupByOccupation)
{
Console.WriteLine(u.Key);
foreach (Useruserinu)
  {
Console.WriteLine(PrintUserObject(user));
  }
}
/*适用于C#版本3*/foreach(ListGroupResultuinUserGroupByOccupation)
{
Console.WriteLine(u.Key);
foreach (Useruserinu.UserList)
  {
Console.WriteLine(PrintUserObject(user));
  }
}
/* 输出结果 */Teacher{id=1, name=ZhangLong, age=38, gender=True, occupation=Teacher}
{id=3, name=ZhangShuai, age=38, gender=False, occupation=Teacher}
Student{id=2, name=ZhangJin, age=18, gender=False, occupation=Student}
{id=9, name=HuZiming, age=21, gender=True, occupation=Student}
{id=10, name=HuJin, age=21, gender=False, occupation=Student}
Doctor{id=4, name=LiuGuangzhi, age=38, gender=False, occupation=Doctor}
{id=5, name=LiuZiming, age=38, gender=True, occupation=Doctor}
{id=6, name=LiuShuai, age=29, gender=False, occupation=Doctor}
Builder{id=7, name=LiuJin, age=21, gender=True, occupation=Builder}
{id=8, name=JiangLong, age=38, gender=True, occupation=Builder}

2、多属性分组查询全部信息

这次,我们根据职业和性别两个属性分组,获得每组的集合:

/* C#版本1 */classListMultiGroupResult{
publicstringOccupation { get; set; }
publicboolGender { get; set; }
publicList<User>UserList { get; set; }
}
IEnumerable<ListMultiGroupResult>UserGroupByOccupationAndGender=list.GroupBy(s=>new { s.occupation, s.gender })
                .Select(g=>newListMultiGroupResult()
                {
Occupation=g.Key.occupation,
Gender=g.Key.gender,
UserList=g.ToList()
                });

这里根据Occupation和Gender分组后一共分为七组:

/* 遍历 输出 *//*适用于C#版本1*/foreach(ListMultiGroupResultuinUserGroupByOccupationAndGender)
{
Console.WriteLine(u.Occupation+"/"+u.Gender);
foreach (Useruserinu.UserList)
  {
Console.WriteLine(PrintUserObject(user));
  }
}
/* 输出结果 */Teacher/True{id=1, name=ZhangLong, age=38, gender=True, occupation=Teacher}
Student/False{id=2, name=ZhangJin, age=18, gender=False, occupation=Student}
{id=10, name=HuJin, age=21, gender=False, occupation=Student}
Teacher/False{id=3, name=ZhangShuai, age=38, gender=False, occupation=Teacher}
Doctor/False{id=4, name=LiuGuangzhi, age=38, gender=False, occupation=Doctor}
{id=6, name=LiuShuai, age=29, gender=False, occupation=Doctor}
Doctor/True{id=5, name=LiuZiming, age=38, gender=True, occupation=Doctor}
Builder/True{id=7, name=LiuJin, age=21, gender=True, occupation=Builder}
{id=8, name=JiangLong, age=38, gender=True, occupation=Builder}
Student/True{id=9, name=HuZiming, age=21, gender=True, occupation=Student}

3、分组并对各组进行数值计算

来看一个SQL中常用的场景例子:

/* SQL里的表达: 按照用户职业分组,查出每个分组的人数及各组的年龄最大值、最小值、平均值和总和 */SELECToccupation,COUNT(id),MAX(age),MIN(age),AVG(age),SUM(age) FROMUSERGROUPBYoccupation;
/* C#版本1 */classAgeGroupResult{
publicstringKey { get; set; }
publicintMaxAge { get; set; }
publicintMinAge { get; set; }
publicdoubleAvgAge { get; set; }
publicintSumAge { get; set; }
}
IEnumerable<AgeGroupResult>userList=fromuinlistgroupubyu.occupationintonselectnewAgeGroupResult()
                  {
Key=n.Key,  //这个Key是occupationMaxAge=n.Max(r=>r.age),
MinAge=n.Min(r=>r.age),
AvgAge=n.Average(r=>r.age),
SumAge=n.Sum(r=>r.age),
                  };



/* 遍历 输出 *//*适用于C#版本1*/foreach (AgeGroupResultuinuserList)
{
Console.WriteLine(PrintAgeGroupObject(u));
}
/* 输出结果 */{Key=Teacher, MaxAge=38, MinAge=38, AvgAge=38, SumAge=76}
{Key=Student, MaxAge=21, MinAge=18, AvgAge=20, SumAge=60}
{Key=Doctor, MaxAge=38, MinAge=29, AvgAge=35, SumAge=105}
{Key=Builder, MaxAge=38, MinAge=21, AvgAge=29.5, SumAge=59}



目录
相关文章
|
1月前
|
SQL 缓存 分布式计算
C#如何处理上亿级数据的查询效率
C#如何处理上亿级数据的查询效率
20 1
|
2月前
|
开发框架 自然语言处理 .NET
C#一分钟浅谈:LINQ 查询表达式的使用技巧
【9月更文挑战第6天】LINQ(Language Integrated Query)是C#开发中的强大工具,使查询数据集合变得简单且接近自然语言。本文从基础入手,通过具体示例讲解LINQ查询表达式的使用技巧,包括过滤、排序和分组等操作。同时,文章还探讨了常见问题及解决方法,如性能优化、过早枚举和类型转换等,帮助开发者写出更高效、易维护的代码。
94 15
|
2月前
|
C#
C#一分钟浅谈:Lambda 表达式和匿名方法
本文详细介绍了C#编程中的Lambda表达式与匿名方法,两者均可用于定义无名函数,使代码更简洁易维护。文章通过基础概念讲解和示例对比,展示了各自语法特点,如Lambda表达式的`(parameters) =&gt; expression`形式及匿名方法的`delegate(parameters)`结构。并通过实例演示了两者的应用差异,强调了在使用Lambda时应注意闭包问题及其解决策略,推荐优先使用Lambda表达式以增强代码可读性。
41 8
|
4月前
|
SQL 开发框架 前端开发
在C#开发中使用第三方组件LambdaParser、DynamicExpresso、Z.Expressions,实现动态解析/求值字符串表达式
在C#开发中使用第三方组件LambdaParser、DynamicExpresso、Z.Expressions,实现动态解析/求值字符串表达式
|
3月前
|
开发框架 .NET C#
WPF/C#:显示分组数据的两种方式
WPF/C#:显示分组数据的两种方式
58 0
|
3月前
|
XML C# 数据格式
WPF/C#:如何将数据分组显示
WPF/C#:如何将数据分组显示
38 0
|
5月前
|
开发框架 .NET 程序员
掌握C#语言的精髓:基础知识与实用技能详解(数据类型与变量+ 条件与循环+函数与模块+LINQ+异常+OOP)
掌握C#语言的精髓:基础知识与实用技能详解(数据类型与变量+ 条件与循环+函数与模块+LINQ+异常+OOP)
33 0
|
6月前
|
C#
C#动态查询:巧用Expression组合多条件表达式
在C#中,利用`Expression`类和`AndAlso`、`OrElse`方法,可以组合两个`Expression&lt;Func&lt;T, bool&gt;&gt;`以实现动态多条件查询。该方法通过构建表达式树,方便地构建复杂查询。示例代码展示了如何创建表达式树,分别检查年龄大于等于18和姓名为&quot;John&quot;的条件,并使用`AndAlso`组合这两个条件,最终编译为可执行的委托进行测试。
250 1
|
13天前
|
C# 开发者
C# 一分钟浅谈:Code Contracts 与契约编程
【10月更文挑战第26天】本文介绍了 C# 中的 Code Contracts,这是一个强大的工具,用于通过契约编程增强代码的健壮性和可维护性。文章从基本概念入手,详细讲解了前置条件、后置条件和对象不变量的使用方法,并通过具体代码示例进行了说明。同时,文章还探讨了常见的问题和易错点,如忘记启用静态检查、过度依赖契约和性能影响,并提供了相应的解决建议。希望读者能通过本文更好地理解和应用 Code Contracts。
28 3
|
1月前
|
安全 C# 数据安全/隐私保护
实现C#编程文件夹加锁保护
【10月更文挑战第16天】本文介绍了两种用 C# 实现文件夹保护的方法:一是通过设置文件系统权限,阻止普通用户访问;二是使用加密技术,对文件夹中的文件进行加密,防止未授权访问。提供了示例代码和使用方法,适用于不同安全需求的场景。