LINQ语法详解
public class Person { public string Name { get; set; } public string Sex { get; set; } public int Age { get; set; } }
List list = new List() { new Person(){ Name="Olive",Sex="女",Age=22}, new Person(){ Name="Moyao",Sex="男",Age=23}, new Person(){ Name="Momo",Sex="女",Age=22}, new Person(){ Name="Only",Sex="女",Age=20}, new Person(){ Name="Love",Sex="女",Age=21}, new Person(){ Name="For",Sex="女",Age=22}, new Person(){ Name="Remote",Sex="男",Age=23}, new Person(){ Name="Snow",Sex="女",Age=23} };
//从list集合中选出性别为“女”的人 var girls = from g in list where g.Sex == "女" select g; //从list集合中选出性别为“男”的人 var boys = list.Where(p => p.Sex == "男"); Console.WriteLine("girl" + System.Environment.NewLine); foreach (var g in girls) { Console.WriteLine("姓名:" + g.Name + "--性别:" + g.Sex + "--年龄:" + g.Age); Console.WriteLine(System.Environment.NewLine); } context.Response.Write("boy" + System.Environment.NewLine); foreach (var b in boys) { Console.WriteLine("姓名:" + b.Name + "--性别:" + b.Sex + "--年龄:" + b.Age); Console.WriteLine(System.Environment.NewLine); }
输出结果如下:
细心的朋友们可能会发现从list集合中获取信息的方式不一样,在获取性别为“女”的集合中采用的是from g in list where g.Sex== "女" select g;
而在获取性别为“男”的集合中采用的为list.Where(p => p.Sex == "男");
或许会有人问,这两种查询方式有什么区别呢?上面的第一种方法叫查询语法(query syntax),看上去和SQL的语句很相似。查询语法使用查询表达式书写。第二种方法叫方法语法(method syntax)是命令形式,它使用的是标准的方法调用,方法是一组叫做标准查询运算符的方法。虽然形式上这两种查询方法不同,事实上这两种方法存在着紧密的联系,在CLR内只识别查询方法,因此在每次查询的时候编译器在编译时会将查询语句翻译为查询方法,当然大部分的查询方法也都有对应的查询语句形式,例如:where对应Where(),select对应Select(),orderby对应orderby(),group对应group(),join对应Join(),distinct对应Distinct(),union对应Union(),Intersect对应Intersect(),except对应Except(),等等。
我们看SQL查询形式:select查询内容 from数据源 where查询条件,也就是分为数据源、查询条件、查询内容这三部分,在LINQ查询里也是分这三部分,从上面的例子中我们可以知道它的查询方式是这样的from a(查询内容) in数据源 where查询条件 select a(查询内容)
下边就从最基本的介绍开始。
1、from
在SQL里边from后跟的是数据源,当然在LINQ里from子句指定的也是要作为数据源使用的数据集合,但是它引入了迭代变量,迭代变量有序表示数据源的每一个元素,最后查询返回的是一个迭代变变量的集合。
2、Where/where()
在SQL里where后跟的是查询条件,在LINQ里也是一样的。
请看示例:
//查询年龄大于21且性别为女的人员的个人信息 var girls1 = from g in list where g.Age > 21 && g.Sex == "女" select g; //使用查询方法查询 var girls1 = list.Where(g => g.Age > 21 && g.Sex == "女"); Console.WriteLine("年龄大于21且性别为女的个人信息:"); foreach (var g in girls1) { Console.WriteLine("姓名:" + g.Name + "--性别:" + g.Sex + "--年龄:" + g.Age); }
实验结果:
从实验结果中我们可以看到,在查询语句中where后边也可以跟一个或多个查询条件,去筛选数据,以得到想要的结果,或许还有人对使用查询方法有点疑问,查询方法where()里边的参数到底是什么呢?这里就用到了上一节我们讲的Lambda表达式。
请看Where()的原型:
where()语法是:
public static IEnumerable where( this IEnumerable source, Func<TSource,bool> predicate)
由上一节学的知识我们可以知道该方法是一个泛型的扩展方法,该方法只接受一个Func<TSource,bool>泛型委托参数,这里的predicate是一个判断条件。
我们上边用的list.Where(g=>g.Age>21 && g.Sex) 高亮部分就相当于一个委托参数,所以用where()查询方法才能查出符合条件的信息。至于上边提到的Selec()、Orderby()等查询方法语法原型都是泛型的扩展方法和where()差不多,后边就不再过多的介绍其方法原型了。
3、select/select()
select筛选出符合条件的数据
用查询语句查询var g1=from g in list where g.Name="Olive" select g1;
用查询方法查询姓名为Olive的人员信息:
var g1 = list.Select(p=>p).Where(p=>p.Name == "Olive");
结果如下:
4、排序:orderby/OrderBy()、thenBy()、ThenByDescending()
//用orderby进行排序(默认升序) Var ps=from p in list select p orderby //用OrderBy()进行排序(升序) var g11 = list.OrderBy(p => p.Age);
结果如图:
//用orderby descending降序排列 var ps=from p in list select p orderby p.Age descending //用OrderByDescending()降序排序 var g11 = list.OrderByDescending(p => p.Age);
结果如图:
用ThenBy()做二次排序,先按年龄的升序排序,如果年龄相等的就再按姓名升序排序
var g12 = list.OrderBy(p => p.Age).ThenBy(p => p.Name);
结果如图:
//用group子句进行分组 Var ps=from p in list group p.Sex into p select p; //使用GroupBy()进行分组 var g11 = list.OrderByDescending(p => p.Age).GroupBy(p=>p.Sex);
用ThenByDescending()做二次排序,先按年龄的升序排序,如果年龄相等的就再按姓名降序排序
var g12 = list.OrderBy(p => p.Age).ThenByDescending(p => p.Name);
结果如图:
5、group/GroupBy()
使用group子句可产生按照指定的键组织的组序列。
//用group子句进行分组 Var ps=from p in list group p.Sex into p select p; //使用GroupBy()进行分组 var g11 = list.OrderByDescending(p => p.Age).GroupBy(p=>p.Sex);
结果如下:
6、Take、TakeWhile、Skip、SkipWhile
6.1、Take:用于从输入序列中返回指定数量的元素
//从满足条件的的序列中返回3条信息
var g12 = list.OrderBy(p => p.Age).ThenByDescending(p => p.Name).Take(3);
6.2、TakeWhile:只要满足一定条件的就会马上返回序列元素
var g12 = list.OrderBy(p => p.Age).ThenByDescending(p => p.Name).TakeWhile(p=>p.Sex=="女");
结果如图:
6.3 、Skip:用于从输入序列中跳过指定个数的元素,返回由序列中剩余的元素所组成的新序列
/跳过4个指定元素,然后将剩余的元素组成新序列返回 var g12 = list.OrderBy(p => p.Age).ThenByDescending(p => p.Name).Skip(4);
6.4、SkipWhile:用于从输入序列中跳过满足一定条件指定数量的元素,返回由序列中剩余的元素所组成的新序列
//跳过姓名为“Olive”的信息,然后将剩余的的元素组成新的序列返回
var g12 = list.OrderBy(p => p.Age).ThenByDescending(p => p.Name).SkipWhile(p=>p.Name=="Olive");
结果如下:
7、Count(),Max()/Min(),Average(),Sum()聚合方法
7.1、Count():统计序列中元素个数
示例:
//求最大年龄: var g121 = list.OrderBy(p => p.Age).ThenByDescending(p => p.Name).Max(p => p.Age); Console.WriteLine("最大年龄为:"+g121);
结果:
示例:
//求最小年龄: var g121 = list.OrderBy(p => p.Age).ThenByDescending(p => p.Name).Min(p => p.Age); Console.WriteLine("最小年龄为:"+g121);
结果:
7.3、Average()求平均值
示例:
//求平均年龄: var g121 = list.OrderBy(p => p.Age).ThenByDescending(p => p.Name).Average(p => p.Age); Console.WriteLine("平均年龄为:"+g121);
结果:
7.4、Sum()累加求和
示例:
//累加年龄: var g121 = list.OrderBy(p => p.Age).ThenByDescending(p => p.Name).Average(p => p.Age); Console.WriteLine("累加年龄为:"+g121);
结果:
8、Join(),GroupJoin(),Union(),Intersect(),Except(),Contact(),Distinct操作符
8.1、Join()用于连接两个序列,和SQL里的Join语句连接多表一样,连接操作接受两个集合然后创建一个临时的对象集合,每个对象包含原始集合对象中的所有字段,使用连接来结合两个或更多个集合中的数据。
例如:
//这里使用上边新建的Person类,然后在新建一个Profession(职业)类 Public class Profession { Public string Name{get;set:} Public string Zhiye{get;set;} } List<Person> list=new List<Person>() { new Person(){ Name="Olive",Sex="女",Age=22}, new Person(){ Name="Moyao",Sex="男",Age=23}, new Person(){ Name="Momo",Sex="女",Age=22}, new Person(){ Name="Only",Sex="女",Age=20}, new Person(){ Name="Love",Sex="女",Age=21}, new Person(){ Name="For",Sex="女",Age=22}, new Person(){ Name="Remote",Sex="男",Age=23}, new Person(){ Name="Snow",Sex="女",Age=23} }; List<Profession> listprofession = new List<Profession> { new Profession() { Name = "Olive", ZhiYe = "会计" }, new Profession() { Name = "Remote", ZhiYe = "IT Coder" }, new Profession() { Name = "BLove", ZhiYe = "学生" }, new Profession(){ Name="AFor",ZhiYe="作家"} }; //使用Join查询语句查询,从Person序列和Profession序列里查询出姓名相同的信息,组合成一个新的序列,并显示姓名和职业 var showzhiye = from p in list join pf in listprofession on p.Name equals pf.Name select new { Name = p.Name, ZhiYe = pf.ZhiYe }; foreach (var p in showzhiye) { Console.WriteLine("姓名:" + p.Name + "职业:" + p.ZhiYe); } //使用Json()方法查询: var showzhiye = list.Join(listprofession, p => p.Name, pf => pf.Name, (p, pf) => new { Name = p.Name, ZhiYe = pf.ZhiYe });
两种方法查询的结果一样如下:
8.2、GroupJoin():将基于键相等对两个序列的元素进行关联并对结果进行分组。使用默认的相等比较器对键进行比较。
var showzhiye = list.GroupJoin(listprofession, p => p.Name, pf => pf.Name, (p, pf) => new{ Name = p.Name, ZhiYe = pf.Max(pf1=>pf1.Name)}); var showzhiye = listprofession.GroupJoin(list, pf => pf.Name, p => p.Name, (pf, p) => new { Name = pf.Name, ZhiYe =pf.ZhiYe, Count=p.Count() });
结果:
8.3、Union():用于将两个输入序列中的元素合并成一个新的序列,且新序列中自动去除重复的序列
示例:
List<Person> list1 = new List<Person>() { new Person(){ Name="Olive",Sex="女",Age=18}, new Person(){ Name="Moyao",Sex="男",Age=19}, new Person(){ Name="Momo",Sex="女",Age=20}, new Person(){ Name="Olive116",Sex="女",Age=18}, new Person(){ Name="Moyao116",Sex="男",Age=19}, new Person(){ Name="Momo116",Sex="女",Age=20}, }; var uniontest = list.Union(list1);//将list1和上边所示的list合并,自动去除重复列 foreach (var p in uniontest) { Console.WriteLine("姓名:" + p.Name + "年龄:"+p.Age +"性别:"+p.Sex ); }
结果:
8.4、Intersect():求两个序列的交集,将两个序列中相同的元素挑选出来组成一个新的序列
这里还是用8.3里的数据源list1、list
示例:
var intersectTest = list1.Intersect(list); foreach (var p in intersectTest) { Console.WriteLine("姓名:" + p.Name + "年龄:"+p.Age +"性别:"+p.Sex ); }
结果:
8.5、Except(),现有A、B两序列,返回仅在A序列中的元素所组成的序列,相当于求差集
var ExceptTest = list.Except(list1);
8.6、Contact():联接两个序列
示例:
var ExceptTest = list.Concat(list1); foreach (var p in ExceptTest) { Console.WriteLine("姓名:" + p.Name + "年龄:"+p.Age +"性别:"+p.Sex ); }
结果: