C# LINQ GroupBy
一、先准备要使用的类:
1、Person类:
class Person
{
public string Name { set; get; }
public int Age { set; get; }
public string Gender { set; get; }
public override string ToString() => Name;
}
2、准备要使用的List,用于分组(GroupBy):
List<Person> personList = new List<Person>
{
new Person
{
Name = "P1", Age = , Gender = "Male" },
new Person
{
Name = "P2", Age = , Gender = "Male",
},
new Person
{
Name = "P2", Age = ,Gender = "Female",
}
};
二、第一种用法:
public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector);
官方释义:根据指定的键选择器函数对序列中的元素进行分组。
我们要分组的集合为source,集合内每个元素的类型为TSource,这里第一个参数keySelector的类型为Func<TSource, TKey>,用于将TSource元素按照由此委托返回的类型TKey进行分组,结果为一个已分好组的集合(集合中的集合)。
编写客户端试验代码如下:
var groups = personList.GroupBy(p => p.Gender);
foreach (var group in groups)
{
Console.WriteLine(group.Key);
foreach(var person in group)
{
Console.WriteLine($"\t{person.Name},{person.Age}");
}
}
以上代码指定的KeySelector是Person类的Gender属性,因此,以上会按照Gender(性别)进行分组,我们使用两个嵌套的foreach循环将分组的内容打印到控制台。
因为groups返回的类型为IEnumerable<IGouping<TKey,TSource>>,因此以上返回的类型为IEnumerable<IGouping<string,Person>>。
IGouping<string,Person>是已经分组后的集合,内部集合元素为Person,且IGouping有一个Key属性,类型为string(指的是Gender属性类型),用于分组的标识。
输出结果如下:
其等价的LINQ语句为:
var groups = from p in personList
group p by p.Gender;
以上的意思可以这样理解:从personList取出p,并对p进行分组,使用分组的依据(Key)为p.Gender,并将分组的结果存储到pGroup,并将分组的结果选择出来合并成一个集合。
三、第二种用法:
public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer);
官方释义:根据指定的键选择器函数对序列中的元素进行分组,并使用指定的比较器对键进行比较。
这种比第一种方法多了一个参数,那就是一个相等比较器,目的是为了当TKey为自定义的类时,GroupBy能根据TKey指定的类根据相等比较器进行分组,
因此,自定义类如何进行分组,GroupBy是不知道的,需要自己定义自己的相等比较器。
首先,将personList更改如下(下划线部分):
List<Person> personList = new List<Person>
{
new Person
{
Name = "P1", Age = , Gender = "Male" },
new Person
{
Name = "P1", Age = , Gender = "Male",
},
new Person
{
Name = "P3", Age = ,Gender = "Female",
}
};
其次,增加一个相等比较器类,用于对Person进行分组:
class PersonEqualityComparer : IEqualityComparer<Person>
{
public bool Equals(Person x, Person y) => x.Name == y.Name;
public int GetHashCode(Person obj) => obj.Name.GetHashCode();
}
其中定义了如何对一个Person相等性定义,只要实现IEqualityComparer<Person>即可,这里以Name作为Person类是否相同的依据。
最后,现在我们对Person类进行分组,编写客户端实验代码如下:
var groups = personList.GroupBy(p => p, new PersonEqualityComparer());
foreach (var group in groups)
{
Console.WriteLine(group.Key.ToString());
foreach(var person in group)
{
Console.WriteLine($"\t{person.Age},{person.Gender}");
}
}
以上的分组依据是Person类,并运用了自己定义的Person类相同比较器,只要Name相同,就分为一组,
输出结果如下:
四、第三种用法:
public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector);
官方释义:根据指定的键选择器函数对序列中的元素进行分组,并且通过使用指定的函数对每个组中的元素进行投影。
这个比第一种用法多了一个elementSelector,第一种用法是对集合本身按照TKey分组,并将自己(TSource)添加到分组内,而当前的用法则可以选择自己想要添加到分组内的元素类型。
编写客户端实验代码如下:
var groups = personList.GroupBy(p => p.Gender, p=>p.Name);
foreach (var group in groups)
{
Console.WriteLine(group.Key.ToString());
foreach(var name in group)
{
Console.WriteLine($"\t{name}");
}
}
以上代码是按照p.Gender进行分组,并将p.Name作为组内的元素。
输出结果如下:
其等价的LINQ语句为:
var groups = from p in personList
group p.Name by p.Gender;
五、第四种用法:
public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, IEnumerable<TSource>, TResult> resultSelector);
官方释义:根据指定的键选择器函数对序列中的元素进行分组,并且从每个组及其键中创建结果值。
这个跟之前的用法都不同,之前的用法都是将结果进行分组,并返回IGrouping<TKey,TSource>对象,而当前用法则是返回自己定义的类型(TResult),在返回自己定义类型之前,将会传入两个参数,一个是TKey,为分组时指定的对象,另外一个则是IEnumerable<TSource>,为分组后的内部对象集合。
编写客户端实验代码如下:
string GetPersonInfo(string gender, IEnumerable<Person> persons)
{
string result = $"{gender}:\t";
foreach (var p in persons)
{
result += $"{p.Name},{p.Age}\t";
}
return result;
}
var results = personList.GroupBy(p => p.Gender,(g, ps) => GetPersonInfo(g,ps));
foreach (var result in results)
{
Console.WriteLine(result);
}
GetPersonInfo为局部方法,见于C#7.0及以上。
以上代码将分组后的内容(一个是TKey,为p.Gender,另外一个是IEnumerable<TSource>,为IEnumerable<Person>)作为字符串输出,因此,将返回的类型为字符串集合。
输出结果如下:
其等价的LINQ语句为:
var results = from p in personList
group p by p.Gender into pGroup
select GetPersonInfo(pGroup.Key, pGroup);
六、第五种用法:
public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer);
官方释义:根据键选择器函数对序列中的元素进行分组。通过使用比较器对键进行比较,并且通过使用指定的函数对每个组的元素进行投影。
与第三种用法基本相同,只是多了一个相等比较器,用于分组的依据。
使用第二种用法的personList及PersonEqualityComparer,编写客户端实验代码如下:
var groups = personList.GroupBy(p => p, p => new { p.Age,p.Gender },new PersonEqualityComparer());
foreach (var group in groups)
{
Console.WriteLine(group.Key.ToString());
foreach (var name in group)
{
Console.WriteLine($"\t{name.Age},{name.Gender}");
}
}
以上代码的分组依据是Person,PersonEqualityComparer则是作为Person分组的比较器,每个组内为一个匿名类型集合。
输出结果如下:
七、第六种用法:
public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, IEnumerable<TSource>, TResult> resultSelector, IEqualityComparer<TKey> comparer);
官方释义:根据指定的键选择器函数对序列中的元素进行分组,并且从每个组及其键中创建结果值。通过使用指定的比较器对键进行比较。
与第四种用法基本相同,只是多了一个相等比较器,用于分组的依据。
使用第二种用法的personList及PersonEqualityComparer,编写客户端实验代码如下:
string GetPersonInfo(Person person, IEnumerable<Person> persons)
{
string result = $"{person.ToString()}:\t";
foreach (var p in persons)
{
result += $"{p.Age},{p.Gender}\t";
}
return result;
}
var results = personList.GroupBy(p => p, (p, ps) => GetPersonInfo(p, ps),new PersonEqualityComparer());
foreach (var result in results)
{
Console.WriteLine(result);
}
以上代码的分组依据是Person,PersonEqualityComparer则是作为Person分组的比较器,每个组内为一个Person集合,并将返回类型为string的字符串输出。
输出结果如下:
八、第七种用法:
public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector);
官方释义:根据指定的键选择器函数对序列中的元素进行分组,并且从每个组及其键中创建结果值。通过使用指定的函数对每个组的元素进行投影。
与第四种方法很类似,只是对分组内的元素进行选择,原有为TSource,现改为TElement。
编写客户端实验代码如下:
string GetPersonInfo(string gender, IEnumerable<string> names)
{
string result = $"{gender}:\t";
foreach (var name in names)
{
result += $"{name}\t";
}
return result;
}
var results = personList.GroupBy(p => p.Gender, (p=>p.Name) ,(g, ns) => GetPersonInfo(g, ns));
foreach (var result in results)
{
Console.WriteLine(result);
}
以上代码将使用Gender分组,并将分组后的信息组合成一条字符串,并输出到控制台。
输出结果如下:
九、第八种用法:
public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector, IEqualityComparer<TKey> comparer);
官方释义: 根据指定的键选择器函数对序列中的元素进行分组,并且从每个组及其键中创建结果值。通过使用指定的比较器对键值进行比较,并且通过使用指定的函数对每个组的元素进行投影。
与第七种用法基本相同,只是多了一个相等比较器,用于分组的依据。
使用第二种用法的personList及PersonEqualityComparer,编写客户端实验代码如下:
var results = personList.GroupBy(p => p, (p=>new { p.Age,p.Gender}),
(p, ns) =>
{
string result = $"{p.ToString()}:\t";
foreach (var n in ns)
{
result += $"{n.Age},{p.Gender}\t";
}
return result;
},new PersonEqualityComparer());
foreach (var result in results)
{
Console.WriteLine(result);
}
以上代码将使用Person分组,使用Person比较器作为分组的依据,并将分组后的信息组合成一条字符串,并输出到控制台。
输出结果如下:
C# LINQ GroupBy的更多相关文章
- Linq GroupBy
//Linq //var result = from p in personList // group p by p.Id // into grouped // select new { Id = g ...
- C# Linq GroupBy 分组过滤求和
var delOrderData = orderLogList.Where(x => (x.OlStatus == 0 && x.OlUpId == null)).GroupBy ...
- 二段Linq Groupby操作
var messages = list.GroupBy(p=>p.RefOrderNo,(k,v)=> new {OrderNo = k,SkuInfo = v}) .Select(p = ...
- LINQ GroupBy 查询数据赋给select
roles.GroupBy(a => new { a.SubjectID,a.SubjectName}).Select(p => new SelectListItem() { Value ...
- 【随记】关于List集合用Linq GroupBy分组过后的遍历小记
List<LeaderKaoQin> lstLeader = new List<LeaderKaoQin>();//一个List集合IGrouping<string, L ...
- atitit. 集合groupby 的实现(2)---自定义linq查询--java .net php
atitit. 集合groupby 的实现(2)---自定义linq查询--java .net php 实现方式有如下 1. Linq的实现原理流程(ati总结) 1 2. groupby 与 事 ...
- atitit. 集合groupby 的实现(2)---自己定义linq查询--java .net php
atitit. 集合groupby 的实现(2)---自己定义linq查询--java .net php 实现方式有例如以下 1. Linq的实现原理流程(ati总结) 1 2. groupby ...
- C#解决Linq OrderBy() 失效的小技巧
前言 前几天的一个数据列表中我用了Linq GroupBy 和OrderBy. 排序在本机正常使用,发到测试后排序死活不对,很是郁闷,总以为是程序问题.于是请教了另外一个同事.有了以下的答案. 问题原 ...
- EntityFramework Core技术线路(EF7已经更名为EF Core,并于2016年6月底发布)
官方文档英文地址:https://github.com/aspnet/EntityFramework/wiki/Roadmap 历经延期和更名,新版本的实体框架终于要和大家见面了,虽然还有点害羞.请大 ...
随机推荐
- [Python]PyCharm中%matplotlib inline报错
%matplotlib作用 是在使用jupyter notebook 或者 jupyter qtconsole的时候,才会经常用到%matplotlib,也就是说那一份代码可能就是别人使用jupyte ...
- Zabbbix之十二------Zabbix实现微信报警通知及创建聚合图形
实战一:实现zabbix监控微信报警 1.在企业微信上注册账号 1.注册企业微信,管理员需要写上自己的真实姓名,扫描以下的二维码,与微信关联真实姓名. 2.登陆企业微信,然后创建一个微信故障通知应用 ...
- 深度优先搜索DFS---求出矩阵中“块”的个数。
题目: 给出一个 m x n 的矩阵,矩阵中的元素为0或1.如果矩阵中有若干个 1是相邻的,那么称这些1构成了一个“块”.求给定的矩阵中“块”的个数. 0 0 0 0 0 0 0 0 0 0 0 0 ...
- Pikachu-Sql Inject(SQL注入)
在owasp发布的top10排行榜里,注入漏洞一直是危害排名第一的漏洞,其中注入漏洞里面首当其冲的就是数据库注入漏洞.一个严重的SQL注入漏洞,可能会直接导致一家公司破产!SQL注入漏洞主要形成的原因 ...
- Wannafly挑战赛13 zzf的好矩阵 题解 答案解释
Wannafly挑战赛13 zzf的好矩阵 题解 文章目录 Wannafly挑战赛13 zzf的好矩阵 题解 分析 结论1 结论2 结论3 C数组对应带子说明 空白长度论述 后续黑色长度论述 能&qu ...
- javascript当中onload用法
7)onload onload就是等页面加载完后才执行. 例 3.7.1 <HEAD> <meta http-equiv="content-type" conte ...
- 【15】ML项目流程与正交化
结构化机器学习项目 一 ML项目流程 1,确立目标(确定开发/测试集 + 唯一最优化指标) 确定开发/测试集:开发/测试集应尽可能接近将来应用场景中的数据. 划分数据集:开发集和测试集大小足以评估模型 ...
- 《80x86汇编语言程序设计教程》第二章课后题答案
2.5 习题 2.1 数据寄存器 1. 八个通用寄存器除了各自规定的专门用途外,它们均可以用于传送和暂存数据,可以保存算术逻辑运算中的各种操作数和运算结果. 2.1 AX和Al寄存器又称为累加器(ac ...
- 牛客寒假6-C汉诺塔
链接:https://ac.nowcoder.com/acm/contest/3007/C来源:牛客网 题目描述 现在你有 N 块矩形木板,第 i 块木板的尺寸是 Xi*Yi,你想用这些木板来玩汉诺塔 ...
- spring-framework核心接口ApplicationContext
核心接口(ApplicationContext) 继承关系 继承接口: org.springframework.beans.factory.ListableBeanFactory:用于访问应用程序组件 ...