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; } }
public class Job { public int JobId { get; set; } //自增ID public string JobName { get; set; } public int WorkAge { get; set; } }
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 });
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 });
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这个东西其实挺好用的,要是用的好可以大大优美代码且减少代码量。还有一些复杂的方法没有讲到,等下次再写。有什么不足的地方希望大神提出来我会改之。
测试代码地址如下:Linq_Lambada