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}



目录
相关文章
|
4月前
|
开发框架 .NET 编译器
C# 10.0中Lambda表达式的改进:更简洁、更灵活的代码编写体验
【1月更文挑战第21天】随着C#语言的不断发展,Lambda表达式作为一种简洁、高效的函数式编程工具,在C# 10.0中迎来了重要的改进。本文将详细探讨C# 10.0中Lambda表达式的新特性,包括参数类型的推断增强、自然类型的Lambda参数以及Lambda表达式的属性改进等。这些改进不仅简化了Lambda表达式的编写过程,还提升了代码的可读性和灵活性,为开发者带来了更优质的编程体验。
|
4月前
|
SQL 开发框架 .NET
C#进阶-LINQ实现对集合的增删改查
本篇演示了LINQ在日常开发中的常用操作,实现结果集的增删改查。目前LINQ支持两种语法,我会在每个案例前先用大家熟知的SQL语句表达,再在后面用C#的两种LINQ语法分别实现。LINQ语法第一次接触难免感到陌生,最好的学习方式就是在项目中多去使用,相信会有很多感悟。
38 0
|
2月前
|
开发框架 .NET C#
C#学习相关系列之Linq用法---where和select用法(二)
C#学习相关系列之Linq用法---where和select用法(二)
|
2月前
|
开发框架 .NET C#
C#学习相关系列之Linq用法---group和join相关用法(三)
C#学习相关系列之Linq用法---group和join相关用法(三)
|
2月前
|
开发框架 .NET C#
C#学习相关系列之Linq常用方法---排序(一)
C#学习相关系列之Linq常用方法---排序(一)
|
2月前
|
开发框架 .NET 编译器
C#学习相关系列之匿名方法和Lambda表达式
C#学习相关系列之匿名方法和Lambda表达式
|
2月前
|
开发框架 安全 .NET
C# .NET面试系列三:集合、异常、泛型、LINQ、委托、EF!
<h2>集合、异常、泛型、LINQ、委托、EF! #### 1. IList 接口与 List 的区别是什么? IList 接口和 List 类是C#中集合的两个相关但不同的概念。下面是它们的主要区别: <b>IList 接口</b> IList 接口是C#中定义的一个泛型接口,位于 System.Collections 命名空间。它派生自 ICollection 接口,定义了一个可以通过索引访问的有序集合。 ```c# IList 接口包含一系列索引化的属性和方法,允许按索引访问、插入、移除元素等。 由于是接口,它只定义了成员的契约,而不提供具体的实现。类似于 IEnumera
159 2
|
3月前
|
SQL 开发框架 .NET
C# Linq SaveChanges()报错 You have an error in your SQL syntex
C# Linq SaveChanges()报错 You have an error in your SQL syntex
11 0
|
4月前
|
开发框架 .NET 编译器
C# 9.0中的目标类型新表达式:类型推断的又一进步
【1月更文挑战第16天】C# 9.0引入了目标类型新表达式,这是类型推断功能的一个重要扩展。通过目标类型新表达式,开发者在创建对象时可以省略类型名称,编译器会根据上下文自动推断所需类型。这一特性不仅简化了代码编写,还提高了代码的可读性和维护性。本文将详细介绍目标类型新表达式的语法、使用场景及其对C#编程的影响。
|
4月前
|
机器学习/深度学习 开发框架 .NET
C# 中的 Lambda 表达式:一种简洁而强大的编程工具
【1月更文挑战第6天】在现代编程中,Lambda 表达式已经成为一种非常流行的编程范式。C# 作为一种功能强大的、面向对象的编程语言,自然也不例外。Lambda 表达式在 C# 中提供了一种简洁、灵活的方式来表示匿名函数。这些函数可以被用作委托或表达式树类型,从而在各种不同的上下文中使用。