0. 写这个文章主要记录下常用 Lambda 的用法, 能力有限, 文中有问题的地方希望各位大神指出来谢谢! 因为平时写代码的时候没有特地去用 lambda, 全是用一些循环, 少量会用到 lambda, 虽然也能实现要的功能, 但是代码量及可读性就没那么好了. 所以重新熟悉了一下 lambda. 对了, 此篇文章大部分内容参考了 shang 神的文章, 部分内容自己补充了一些.
一. 常用方法及说明
1.1 先准备如下类及列表用于实操
- public class Person
- {
- public int PId { get; set; } // 自增 ID
- public string Name { get; set; }
- public int Age { get; set; }
- public int JobId { get; set; }
- }
- Person
- public class Job
- {
- public int JobId { get; set; } // 自增 ID
- public string JobName { get; set; }
- public int WorkAge { get; set; }
- }
- Job
- List<Person> pA = new List<Person>();
- pA.Add(new Person() { PId = 1, Name = "张三", Age = 16, JobId = 1 });
- pA.Add(new Person() { PId = 2, Name = "小红", Age = 18, JobId = 2 });
- pA.Add(new Person() { PId = 3, Name = "王武", Age = 20, JobId = 3 });
- pA.Add(new Person() { PId = 4, Name = "小梅", Age = 17, JobId = 4 });
- pA.Add(new Person() { PId = 5, Name = "小李", Age = 24, JobId = 3 });
- PersonList
- List<Job> jB = new List<Job>();
- jB.Add(new Job() { JobId = 1, JobName = "制造业", WorkAge = 3 });
- jB.Add(new Job() { JobId = 2, JobName = "IT 行业", WorkAge = 5 });
- jB.Add(new Job() { JobId = 3, JobName = "建筑业", WorkAge = 2 });
- jB.Add(new Job() { JobId = 4, JobName = "金融业", WorkAge = 1 });
- jBList
1.2 主要操作方法
1.2.1 Select(将序列中的每个元素投影到新表中)
即当你只是需要序列中每个元素某个或者某些字段时, 可使用 Select
- // 返回 Name 字段列表
- var result = pA.Select(k => k.Name).ToList();
- // 加上 index, 并且返回一个匿名函数
- var result0 = pA.Select((k,index) => new { index = index,person = k}).ToList();
result 返回了 Name 字段的列表
result0 返回了一个匿名类的对象列表, 匿名类有两个字段: index(下标),person 对象
1.2.2 Where(基于谓词筛选值序列)
即筛选序列中符合条件的元素并返回新列表
- // 筛选出 Age 大于 18 的记录
- var result1 = pA.Where(k => k.Age> 18).ToList();
- //r 参数代表元素在集合中的索引
- var result112 = pA.Where((k,r) =>
- {
- if (r <= 3)
- return false;
- return k.Age> 18;
- }
- ).ToList();
- // 筛选出 Age 大于 18 并且 JobId 等于 3 的记录
- var result2 = pA.Where(k => k.Age> 18 && k.JobId==3 ).ToList();
- // 筛选出 Age 大于 18 或者 JobId 等于 3 的记录
- var result3 = pA.Where(k => k.Age> 18 || k.JobId == 3).ToList();
result1 筛选出 Age 大于 18 的记录
result112 筛选出 Age 大于 18 并且下标大于 3 的记录
result2 筛选出 Age 大于 18 并且 JobId 等于 3 的记录
result3 筛选出 Age 大于 18 或者 JobId 等于 3 的记录
- 1.2.3
- Single(返回序列的唯一元素; 如果该序列并非恰好包含一个元素, 则会引发异常.)
- SingleOrDefault(返回序列中的唯一元素; 如果该序列为空, 则返回默认值; 如果该序列包含多个元素, 此方法将引发异常.)
- First(返回序列中的第一个元素.)
- FirstOrDefault(返回序列中的第一个元素; 如果序列中不包含任何元素, 则返回默认值.)
- Last(返回序列的最后一个元素.)
- LastOrDefault(返回序列中的最后一个元素; 如果序列中不包含任何元素, 则返回默认值.)
以上这六个方法用法类似, 目的都是为返回一个元素. 后缀有 Default 就是当序列没有满足条件的元素时, 返回为空.
- // 返回满足指定条件的元素, 若为空或返回数量不止一个, 则抛异常
- var result171 = pA.Single(r => r.JobId == 2);
- // 返回满足指定条件的元素, 若为空, 则返回空; 若返回数量不止一个, 则抛异常
- var result172 = pA.SingleOrDefault(r => r.JobId == 2);
- // 返回满足指定条件的对象列表中的第一个元素, 若为空, 则抛异常
- var result173 = pA.First(r => r.JobId == 2);
- // 返回满足指定条件的对象列表中的第一个元素, 若为空, 则返回空
- var result174 = pA.FirstOrDefault(r => r.JobId == 2);
- // 返回满足指定条件的对象列表中的最后一个元素, 若为空, 则抛异常
- var result175 = pA.Last(r => r.JobId == 2);
- // 返回满足指定条件的对象列表中的最后一个元素, 若为空, 则返回空
- var result176 = pA.LastOrDefault(r => r.JobId == 2);
- 1.2.4
- OrderBy(根据键按升序对序列的元素排序.)
- OrderByDescending(根据键按降序对序列的元素排序.)
- ThenBy(根据某个键按升序对序列中的元素执行后续排序.)
- ThenByDescending(根据某个键按降序对序列中的元素执行后续排序.)
即对序列进行排序.
- // 先筛选出 Age 大于 10 的记录, 再根据 Age 列升序 / 正序输出
- var result6 = pA.Where(k => k.Age> 10)
- .OrderBy(k => k.Age).ToList();
- // 先筛选出 Age 大于 10 的记录, 再按 Age 倒序, 再按 JobId 正序, 再按名称倒序.
- var result8 = pA.Where(k => k.Age> 10).OrderByDescending(k => k.Age)
- .ThenBy(k => k.JobId).ThenByDescending(k => k.Name).ToList();
result6 返回了按照 Age 字段升序排列的列表
result8 返回了先按照 Age 字段降序, 再按照 JobId 升序, 再按照 Name 字段降序的列表
- 1.2.5
- GroupBy(根据指定的键选择器函数对序列中的元素进行分组.)
- ToDictionary(根据指定的键选择器函数, 从 System.Collections.Generic.IEnumerable`1 创建一个 System.Collections.Generic.Dictionary`2.)
GroupBy 可以对序列进行分组, ToDictionary 可以将序列转成字典.
- var result4 = pA.Where(k => k.Age> 10).GroupBy(j => j.JobId).Select(l => l.Key).ToList();
- var result41 = pA.Where(k => k.Age> 10).GroupBy(j => j.JobId);
- var result42 = result41.ToDictionary(r => r.Key);
- var result43 = result41.ToDictionary(r => r.Key,rr=>rr.Select(r=>r.Name));
- var result5 = pA.Where(k => k.Age> 10)
- .GroupBy(a => new Person { PId = a.PId, Name = a.Name, Age = a.Age, JobId = a.JobId })
- .Select(a => a.Key).ToList();
result4 先筛选出 Age 大于 10 的元素, 再根据 JobId 字段分组 (分组的字段即为 Key), 再选择键(Key) 返回
result41 先筛选出 Age 大于 10 的元素, 再根据 JobId 字段分组(分组的字段即为 Key)
result42 在 result41 的基础上将分组后内容转成字典, 键选择了分组时的 Key, 值默认是分组时的 element
result43 在 result41 的基础上将分组后内容转成字典, 键选择了分组时的 Key, 值选择了分组时的 element 中的 Name 字段
result5 先筛选出 Age 大于 10 的元素, 再根据 Persson 对象分组, 再选择键 (Key) 返回(此处的 key 为 Person 对象)
- 1.2.6 Average,Sum,Min,Max(平均值 / 求和 / 最大值 / 最小值)
- // 获取 Age 的平均值
- var result10 = pA.Average(k => k.Age);
- // 获取 Age 的平均值
- var result101 = pA.Sum(k => k.Age);
- var result201 = pA.Min(r => r.Age);
- var result202 = pA.Max(r => r.Age);
- 1.2.7
- All(确定序列中的所有元素是否满足条件.)
- Any(确定序列是否包含任何元素./ 确定序列是否包含满足条件的元素.)
- var result211 = pA.All(r => r.Age> 18);
- var result212 = pA.Any(r => r.Age> 18);
- var result213 = pA.Any();
result211 中只有 PA 列表所有元素的 Age 大于 18, 才返回 True
result212 中 PA 列表任一元素的 Age 大于 18, 即返回 True
result213 中 PA 列表不为空时返回 True
- 1.2.8 Repeat(生成包含一个重复值的序列.)
- var result191 = Enumerable.Repeat(pA.First(), 10);
result191 返回了有十条 pA.First()元素的序列
- 1.2.9
- Cast(将 System.Collections.IEnumerable 的元素强制转换为指定的类型.)
- OfType(根据指定类型筛选 System.Collections.IEnumerable 的元素.)
- var result221 = pA.Cast<object>();
- var result222 = pA.OfType<Job>();
result221 中将 pA 序列中所有元素强转成 object 类型(实际使用应该会转其他类型)
result222 从 pA 序列中筛选出类型为 Job 的元素并返回
- 1.2.10
- Take(从序列的开头返回指定数量的连续元素.)
- TakeWhile(只要满足指定的条件, 就会返回序列的元素.)
- Skip(跳过序列中指定数量的元素, 然后返回剩余的元素.)
- SkipWhile(只要满足指定的条件, 就跳过序列中的元素, 然后返回剩余元素.)
- // 先筛选出 Age 大于 10 的记录, 再取前三条记录
- var result154 = pA.Where(o => o.Age> 10).Take(3).ToList();
- // 从 index=0 开始, 若符合条件, 则取出并继续下一个, 否则. 停止.(与 Where 不同)
- var result155 = pA.TakeWhile(k => k.Age> 18).ToList();
- var result156 = pA.TakeWhile((k, index) => index <2).ToList();
- var result161 = pA.Skip(2);
- // 从 index=0 开始, 若符合条件, 则跳过该继续下一个, 否则. 停止.
- var result162 = pA.SkipWhile(r => r.JobId == 3);
- var result163 = pA.SkipWhile((r,index) => index <= 3);
result154 先筛选出 Age 大于 10 的记录, 再取前三条记录
result155 从 pA 序列的 index=0 开始, 若元素符合条件(此处是 Age 大于 18), 则取出并继续下一个判断, 否则, 停止判断并返回之前取出符合条件的元素.(与 Where 不同)
result155 从 pA 序列的 index=0 开始, 若元素符合条件(此处是 index 小于 2), 则取出并继续下一个判断, 否则, 停止判断并返回之前取出符合条件的元素.(与 Where 不同)
result161 先跳过 pA 前两个元素, 再返回剩下的序列
result162 从 pA 序列的 index=0 开始, 若元素符合条件(此处是 JobId 等于 3), 则跳过该元素并继续下个元素的判断. 否则, 停止判断并返回当前元素以及剩下元素的序列.
result162 从 pA 序列的 index=0 开始, 若元素符合条件(此处是 index 小于 3), 则跳过该元素并继续下个元素的判断. 否则, 停止判断并返回当前元素以及剩下元素的序列.
- 1.2.11 Join(基于匹配键对两个序列的元素进行关联. 使用默认的相等比较器对键进行比较.)
- var result12 = pA.Join(jB, j => j.JobId, k => k.JobId, (j, k) => new { j.PId, j.Name, j.Age, k.JobName }).ToList();
pA 和 jB 分别是两个需要进行连接的序列, 关联的字段为 pA 的 JobId 和 jB 的 JobId 字段, 返回一个匿名类对象, 包含 pA 的 PId,Name,Age 和 jB 的 JobName 字段
- 1.2.12 SelectMany(将序列的每个元素投影到 System.Collections.Generic.IEnumerable`1 并将结果序列合并为一个序列.)
- public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector);
- public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, IEnumerable<TResult>> selector);
- public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector);
- // 返回的是 IEnumerabele<string > 类型
- var result181 = pA.SelectMany(r => new List<string>()
- {
- r.Name,
- r.Age.ToString()
- });
- var result182 = pA.SelectMany((r,index) => new List<string>()
- {
- r.Name,
- r.Age.ToString(),
- index.ToString()
- });
- // 返回结果为 List<object>, 其中 r 为 Person 类, rr 为第一步返回的 List<string>
- var result183 = pA.SelectMany(r => new List<string>()
- {
- r.Name,
- r.Age.ToString()
- },(r,rr) => new List<object>
- {
- r.JobId,
- rr
- });
result181 返回的序列中将会把原始序列中每个元素的 Name 和 Age 字段单独形成一个元素并返回, 即新序列的长度为原始序列长度的两倍.
result182 返回的序列中将会把原始序列中每个元素的 index,Name 和 Age 字段单独形成一个元素并返回, 即新序列的长度为原始序列长度的三倍.
result183 方法中第一个参数与 result181 相同, 第二个参数将原始序列中的元素和第一个参数返回的序列中的元素作为新参数, 返回新的序列.
二. 总结 Linq 这个东西其实挺好用的, 要是用的好可以大大优美代码且减少代码量. 还有一些复杂的方法没有讲到, 等下次再写. 有什么不足的地方希望大神提出来我会改之.
测试代码地址如下: https://files.cnblogs.com/files/liyijin/Linq_Lambada.rar
来源: https://www.cnblogs.com/liyijin/p/9250980.html