C#笔记 -- LINQ方法
public class Emp { public string Id { get; set; } public int Age { get; set; } public string Name { get; set; } public double Salary { get; set; } public bool Gender { get; set; } }
List<Emp> empList = new List<Emp> { new Emp { Id= "1", Age = 1, Name = "mark" , Salary = 111.0, Gender = true}, new Emp { Id= "2", Age = 1, Name = "amy", Salary = 111.0, Gender = false}, new Emp { Id= "3", Age = 2, Name = "bob", Salary = 112.0, Gender = true} };
一、委托
-
委托是可以指向方法的类型, 调用委托变量时执行的就是变量指向的方法
-
.net定义了泛型委托
Action
(无返回值)、Func
(有返回值), 所以一般不用自定义委托类型
Action<in T1, ..., in T16> action;//0~16个入参, 无返回值 Func<in t1, ..., in T16, out TResult>func; //0~16个入参, 返回值TResult
二、匿名方法
-
以
delegate
声明的方法
Action<in T1, ..., in T16> action = delegate(T1 t1, ..., T16 t16) { //操作 };
Func<in T1, ..., in T16, out TResult> action = delegate(T1 t1, ..., T16 t16) { //操作 return tResult; };
-
可以采用
lambda
表达式简化
Action<in T1, ..., in T16> action = (t1, ..., t16) => { //操作 };
Func<in T1, ..., in T16, out TResult> action = (t1, ..., t16) => { //操作 return tResult; };
三、LINQ常用扩展方法
1、IEnumerable<T> Where(predicate)
-
predicate返回true, 这个元素就会放到返回值中
-
predicate可以匿名委托写, 也可以用Lambda表达式
List<int> beforeList = new List<int> { 1, 2, 3 }; IEnumerable<int> enumerable = beforeList.Where(e => e > 2);
2、int Count(predicate)
-
返回满足predicate的元素个数
List<int> beforeList = new List<int> { 1, 2, 3 }; int count = beforeList.Count(e => e > 2);
3、bool Any(predicate)
-
返回是否至少有一个满足predicate的元素
List<int> beforeList = new List<int> { 1, 2, 3 }; bool hasAny = beforeList.Any(e => e > 2);
4、获取一条数据
(1)T Single(predicate)
-
获取有且只有一条满足要求的数据
-
没获取到就报错
-
有多条就报错
(2)T SingleOrDefault(predicate)
-
获取有且只有一条满足要求的数据
-
没获取到就返回
T
类型的默认值 -
有多条就报错
(3)T First(predicate)
-
获取第一条满足要求的数据
-
没获取到就报错
(4)T FirstOrDefault(prediate)
-
获取第一条满足要求的数据
-
没获取到就返回
T
类型的默认值
5、排序
(1)IEnumerable<T> OrderBy([选填]排序依据)
正序
(2)IEnumerable<T> OrderByDescending([选填]排序依据)
倒序
(3)排序特殊案例
A.按照属性最后一个字符排序
public class T { public string StrProp { get; set; } }
IEnumberable<T> list2 = list.OrderBy(e => e.StrProp[e.StrProp.Length-1]);
B.用Guid
或者随机数进行随机排序
IEnumerable<T> list2 = list.OrderBy(e => Guid.NewGuid());
(4)多排序规则ThenBy(排序依据)
、ThenByEdscending(排序依据)
-
可以在
Order()
、OrderByDescending()
后继续写ThenBy()
、ThenByDescending()
例子: 优先按照Age正序, 如果Age相同再按照Salary倒序
empList .OrderyBy(e => e.Age) .ThenByDescending(e => e.Salary);
6、限制结果集
(1)IEnumerable<T> Skip(n)
跳过n条数据
(2)IEnumerable<T> Take(n)
获取n条数据
案例: 从第2条开始获取3条数据
list.Skip(2).Take(3);
四、聚合函数
函数 | 描述 |
---|---|
Max() |
求最大 |
Min() |
求最小 |
Average() |
求平均 |
Sum() |
求和 |
Count() |
求个数 |
1、IGrouping<TKey, TSource> GroupBy(分组字段值)
分组函数
-
GroupBy()
可以和聚合函数一起用, 表示分组的聚合 -
IGrouing
-
继承自
IEnumerable
-
Key
属性表示这一组的分组数据的字段值
-
-
使用分组函数后, 后面的链式操作, 全部变为对组操作, 而不是对元素
-
后面对于组的操作, 可以从组中再获取元素, 比如使用投影
empList.Where(e => "2".CompareTo(e.Id) < 0) .GroupBy(e => e.Age) //分完了组, 此刻开始只能对组操作 .OrderBy(g => g.Key) .Take(3) //Select拆组, 对元素操作 .Select(g => new { Age = g.Key, Total = g.Count(), AvgSalary = g.Average(e => e.Salary) });
例子: 查询每一组年薪最高
//分组 IEnumerable<IGrouping<int, Emp>> empGroupByAge = empList.GroupBy(e => e.Age); //遍历每个组 foreach (IGrouping<int, Emp> group in empGroupByAge) { //求每个组米最多 double highestSalary = group.Max(e => e.Salary); //Key就是Age, 分组条件就是年龄 Console.WriteLine($"{group.Key}组, 钱最多的¥{highestSalary}"); //遍历当前组, 获取当前组中的每一个Emp foreach (Emp emp in group) { Console.WriteLine($"年龄: {emp.Age}, 名字: {emp.Name}"); } Console.WriteLine("--------------------"); }
例子: 查询每一组年薪最高的人
//<分组的键的值, 每组钱最多的人集合> Dictionary<int, List<Emp>> mostRichEmpDic = new Dictionary<int, List<Emp>>(); foreach (var g in empList.GroupBy(e => e.Age)) { double maxSalary = g.Max(e => e.Salary); //每组钱最多的人集合 IEnumerable<Emp> mostRichEmps = g.Where(e => e.Salary == maxSalary); mostRichEmpDic[mostRichEmps.First().Age] = mostRichEmps.ToList(); }
五、投影
1、IEnumberable<TResult> Select(转换方式)
-
把集合中的每一项转换为另一种类型
//把集合中的每一项转换为int IEnumberable<int> ages = list.Select(e => e.Age); //把集合中的每一项转换为性别 IEnumerable<string> empGenders = empList.Select(e => e.Gender ? "male" : "female"); //转换人员集合为人类匿名集合 var personList = empList.Select(e => new { e.Name, Gender = e.Gender ? "男" : "女" });
-
根据分组结果生成集合
//根据年龄生成最高和最低薪资的集合 empList.GroupBy(e => e.Age).Select(g => new { AgeArea = g.Key, MaxSalary = g.Max(e => e.Salary), MinSalary = g.Min(e => e.Salary), AreaTotal = g.Count() });
-
根据年龄分组, 并投影最低和最高薪资的人的匿名集合
empList.GroupBy(e => e.Age).Select(g => new { AgeArea = g.Key, MaxSalary = g.Max(e => e.Salary), MaxEmps = g.Where(e => e.Salary == g.Max(e => e.Salary)), MinSalary = g.Min(e => e.Salary), MinEmps = g.Where(e => e.Salary == g.Min(e => e.Salary)), AreaTotal = g.Count() });
六、集合转换
-
需要使用数组或者列表类型的变量
1、T[] IEnumerable<T>.ToArray()
Emp[] emps = empList.Where(e => "bob".Equals(e.Name)).ToArray();
2、List<T> IEnumerable<T>.ToArray()
List<Emp> empAfterList = empList.Where(e => "bob" == e.Name).ToList();
七、链式调用
-
Where()
、Select()
、OrderBy()
、GroupBy()
等返回值都是或者继承IEnumerable<T>
类型, 所以可以链式调用
例子: 获取ID>2的数据, 然后按照Age分组, 并且把分组按照Age排序, 取出前3条, 最后再投影取得年龄、人数、平均工资
empList.Where(e => "2".CompareTo(e.Id) < 0) .GroupBy(e => e.Age) .OrderBy(g => g.Key) .Take(3) .Select(g => new { Age = g.Key, Total = g.Count(), AvgSalary = g.Average(e => e.Salary) });
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2022-10-01 leetcode-sql-626. 换座位 order by if