Linq 基础学习
什么是LINQ
- LINQ(发音为link)代表语言集成查询(Language Integrated Query)
- 详细见LINQ
匿名类型
第一个成员初始化器是赋值形式,第二个是成员访问表达式,第三个是标示符形式,如下实例所示:
- string Sex = "男";
- var person = new { Age = 24, SimpleClass.Name, Sex };
- Console.WriteLine("{0},Sex{1},Age {2}",person.Name,person.Sex,person.Age);
运行结果:
注意标示符形式和访问表达式必须定义在匿名类型申明之前,Sex是一个局部变量,Name是类SimpleClass的静态字段。
尽管在代码中看不到匿名类型,对象浏览器却能看到。如果编译器遇到了另一个具有相同参数名、相同引用类型名和相同顺序的匿名类型,它会重用这个类型并直接创建新的实例,而不会创建新的匿名类型。
查询语法和方法语法
- 查询语法(query syntax)是声明形式的,看上去和SQL的语句很相似。查询语法使用查询表达式书写。
- 方法语法(method syntax)是命令形式,它的使用是标准的方法调用。方法是一组叫做标准查询运算符的方法。
- 在一个查询中也可以组合以上两种形式。
示例代码如下所示:
1 var query1 = from n in Enumerable.Range(1, 10) 2 where n < 8 3 select n; 4 Console.Write("查询语法得到结果:"); 5 foreach (var v in query1) Console.Write("{0}\t",v); 6 7 var query2 = Enumerable.Range(1, 8).Where(n => n < 8); 8 Console.WriteLine(""); 9 Console.Write("方法语法得到结果:"); 10 foreach (var v in query2) Console.Write("{0}\t", v); 11 12 int count = (from n in Enumerable.Range(1, 10) 13 where n < 8 14 select n).Count(); 15 Console.WriteLine(""); 16 Console.WriteLine("两种方式的组合:{0}", count);
运行结果:
查询表达式的结构
1、from子句
- from子句指定了要作为数据源使用的数据集合。它也引入了迭代变量,迭代变量有序表示数据源的每一个元素。
- int[] arr = { 1, 5, 9, 8, 45, 23, 26, 14, 7, 8, 9 };
- var query = from n in arr //(n->迭代变量)
- where n < 10 //使用迭代变量
- select n; //使用迭代变量
- foreach (var v in query) Console.Write("{0}\t",v);
- Console.WriteLine("");
运行结果:
2、join子句
- LINQ中的join子句和SQL中的join很相似,连接操作接受两个集合然后创建一个临时的对象集合,每个对象包含原始集合对象中的所有字段,使用连接来结合两个或更多个集合中的数据。
示例代码如下:
1 public class Student 2 { 3 public int StID; 4 public string LastName; 5 } 6 public class CourseStudent 7 { 8 public string CourseName; 9 public int StID; 10 } 11 12 CourseStudent[] studentInCourses = new CourseStudent[]{ 13 new CourseStudent{CourseName="Art",StID=1}, 14 new CourseStudent{CourseName="Art",StID=3}, 15 new CourseStudent{CourseName="History",StID=1}, 16 new CourseStudent{CourseName="History",StID=2}, 17 new CourseStudent{CourseName="Physics",StID=3} 18 }; 19 Student[] students = new Student[] { 20 new Student{StID=1,LastName="张三"}, 21 new Student{StID=2,LastName="李四"}, 22 new Student{StID=3,LastName="王五"} 23 }; 24 25 //获取选修2门课以上同学的名字 26 var query = (from s in students 27 join c in studentInCourses on s.StID equals c.StID 28 where (from x in studentInCourses where x.StID==c.StID select x.StID).Count()>1 29 select s.LastName).Distinct(); 30 foreach (var v in query) Console.Write("{0}\t",v); 31 Console.WriteLine(""); 32 //获取选修历史同学的名字 33 var query1 = from s in students 34 join c in studentInCourses on s.StID equals c.StID 35 where c.CourseName == "History" 36 select s.LastName; 37 foreach (var v in query1) Console.Write("{0}\t", v);
运行结果:
查询主体中的from...let...where片段
- 可选的from...let...where部分是查询主体的第一部分,可以由任意数量的3个子句来组合--from子句、let子句和where子句。
1、from子句
- 查询表达式必须从from子句开始,后面跟的是查询主体。主体本身可以从任何数量的其他from子句开始,每一个from子句都指定了一个额外的数据源集合并引入了要在之后运算的迭代变量,所有from子句的语法和含义都是一样的。
示例代码如下:
- var someInts = from a in Enumerable.Range(1, 5) //必须的第一个from子句
- from b in Enumerable.Range(6, 5) //查询主体的第一个子句
- where a < 3 && b < 10
- select new { a, b, sum = a + b }; //匿名类型对象
- foreach (var v in someInts) Console.WriteLine(v);
2、let子句
- let子句接受一个表达式的运算并把它赋值给一个需要在其他运算中使用的标示符。
示例代码如下:
1 var someInts = from a in Enumerable.Range(1, 5) 2 from b in Enumerable.Range(6, 5) 3 let sum = a + b //在新的变量中保存结果 4 where sum == 12 5 select new { a, b, sum }; 6 foreach (var v in someInts) Console.WriteLine(v);
运行结果:
3、where子句
- where子句根据之后的运算来去除不符合指定条件的项。
示例代码如下:
- var someInts = from a in Enumerable.Range(1, 5)
- from b in Enumerable.Range(6, 5)
- let sum = a + b
- where sum > 12 //条件一
- where a==4 //条件二
- select new { a, b, sum };
- foreach (var v in someInts) Console.WriteLine(v);
运行结果:
orderby子句
- orderby子句接受一个表达式并根据表达式依次返回结果项,orderby子句的默认排序是升序,然而我们可以使用ascending和descending关键词显示第设置元素排序为升序或降序,ordery可以有任意多个子句,它们必须用逗号隔开。
示例代码如下:
1 var persons = new[] { //匿名类型的对象数组 2 new {Name="张三",Sex="男",Age=32,Address="广东深圳"}, 3 new {Name="李四",Sex="男",Age=26,Address="广东广州"}, 4 new {Name="王五",Sex="女",Age=22,Address="广东深圳"}, 5 new {Name="赵六",Sex="男",Age=33,Address="广东东莞"} 6 }; 7 var query = from p in persons 8 orderby p.Age 9 select p; 10 foreach (var p in query) Console.WriteLine("Name:{0},Sex:{1},Age:{2},Address:{3}", p.Name, p.Sex, p.Age, p.Address);
运行结果:
group by子句
- group子句把select的对象根据一些标准进行分组。例如,有了前面示例人的数组,程序可以根据它们的所在地进行分组。
- group by如果项包含在查询结果中,它们就可以根据某个字段的值进行分组。作为分组依据的项叫做键(key);和select子句不同,group子句不从原始的数据源中返回可枚举的可枚举类型,而是返回以枚举已经形成的项的分组的可枚举类型;分组本身是可枚举类型,它们可枚举实际的项。
示例代码如下:
- var persons = new[] { //匿名类型的对象数组
- new {Name="张三",Sex="男",Age=32,Address="广东深圳"},
- new {Name="李四",Sex="男",Age=26,Address="广东广州"},
- new {Name="王五",Sex="女",Age=22,Address="广东深圳"},
- new {Name="赵六",Sex="男",Age=33,Address="广东东莞"}
- };
- var query = from p in persons
- group p by p.Address;
- foreach (var v in query) //枚举分组
- {
- Console.WriteLine("{0}",v.Key); //分组键
- foreach (var t in v) //枚举分组中的项
- {
- Console.WriteLine("Name:{0},Sex:{1},Age:{2},Address:{3}", t.Name, t.Sex, t.Age, t.Address);
- }
- }
运行结果:
查询延续
- 查询延续子句可以接受查询的一部分结果并赋予一个名字,从而可以查询的另一部分中使用。
示例代码如下:
1 var somInts = from a in Enumerable.Range(1, 10) 2 join b in Enumerable.Range(5, 10) on a equals b 3 into groupTemp //查询延续 4 from c in groupTemp 5 select c; 6 foreach (var v in somInts) Console.WriteLine(v);
运行结果如下:
使用委托参数和Lambda的示例
public static int Count<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
示例代码如下:
- IList<int> list = Enumerable.Range(1, 100).ToList();
- Func<int, bool> myDel = delegate(int x) { return x % 2 == 1; };//委托匿名方法
- var countOdd1 = list.Count(myDel);//调用委托
- var countOdd2 = list.Count(x => x % 2 == 1);//Lambda表达式
- Console.WriteLine("委托参数得到奇数的个数:{0}",countOdd1);
- Console.WriteLine("Lambda得到奇数的个数:{0}", countOdd2);
运行结果:
一切伟大的行动和思想,都有一个微不足道的开始。微不足道的我,正在吸取知识的土壤,希望能取得成功!不嫌弃我微不足道的,愿交天下好友!