• C# 一周入门高级编程之《C#-LINQ》Day Four


    一、C# LINQ 是什么

    C# 的LINQ语法类似数据库的查询方法,是一种数据集合的查询语法,LINQ可以直接查询数据库、泛型、以容器、以及xml文档。什么意思呐?我们对于一个集合可能操作就是通过循环,给出判断条件,然后满足条件的话就把这个元素添加到一个新的集合内返回就行啦,但是C#提供了另外的方法,就是用LINQ查询语法,用类似SQL语法对可查询对象进行筛选,就这个开发效率就很高了,而且这样的写法还很方便。

    • 这篇文章主要是讲述 基本的 LINQ 对于泛型、容器的一些操作,
    • 数据库部分、xml文档部分我暂时没有研究。分组以及连接部分暂未深入掌握

    二、LINQ基础用法

    初次尝试使用LINQ语法,下面有对几种集合类型进行查询例子,语法非常容易懂,可以工具可以好好利用。
    使用LINQ有三个步骤。

    • 指定数据源
    • 创建查询语句
    • 执行查询

    如下面 代码例子所示

    1. 对数组查询

    如下对数组进行查询 大于100的元素

    //创建数据源
    int[] intList = { 32, 35, 43, 654, 76, 56, 57, 453, 3542, 46 };
    
    //创建查询语句
    IEnumerable<int> searchRes = from item in intList
    							 where item >100
    							 select item;
    
    //执行查询
    foreach(var item in searchRes)
    {
    	Console.WriteLine(item);
    }
    
    //结果如下
    654
    453
    3542
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2. 对容器查询

    如下对字符串列表查询

    //创建数据源
    List<string> stringList = new List<string>() {"Helan","Linken", "Black", "Brownd", "Kindey" };
    
    //创建查询语句
    IEnumerable<string> stringSearchList = from item in stringList
                                       	   where item.StartsWith("B") || item.StartsWith("K")
                                           select item;
                                           
    //执行查询
    foreach(var item in stringSearchList)
    {
    	Console.WriteLine(item);
    }
    //结果如下
    Black
    Brownd
    Kindey
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3. 对IEnumerable<>查询

    //创建数据源
    IEnumerable<double> doubeList = new double[]{ 32.4, 3.25, 35.4, 3.65, 4.74, 3.575, 4.6675 };
    
    //创建查询语句
    var doubleSearchList = from item in doubeList
    					   where item > 20.11
    					   select item;
    
    //执行查询
    foreach(var item in doubleSearchList)
    {
    	Console.WriteLine(item);
    }
    
    //结果如下
    32.4
    35.4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    4. 非泛型(IEnumerable)如 ArrayList

    对 这种非泛型查询需要指定 数据 对象的类型, 不然推断不出来是什么类型 ,因为其实泛型已经指明了数据项的类型

    //创建数据源
    ArrayList arrayList = new ArrayList() { 42, 34, 43, 434, -4, 354, 65, 754, 7, -43, 764, 2, };
    
    //创建查询语句
    var arrayListRes = from int item in arrayList
                                   where item <= 0
                                   select item;
    
    //执行查询
    foreach(var item in arrayListRes)
    {
    	Console.WriteLine(item);
    }
    
    //查询结果
    -4
    -43
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    三、获取数据源

    所谓获取数据源,其实在上面例子中已经说明很清晰啦,数据源其实就是一个数据集合,我们需要指定一个集合作为我们查询的基础条件,在 LINQ 查询中,第一步是指定数据源。 在 LINQ 查询中,先使用 from 子句引入数据源以及数据项。

    • 如下:
    //创建数据源
    IEnumerable<double> doubeList = new double[]{ 32.4, 3.25, 35.4, 3.65, 4.74, 3.575, 4.6675 };
    
    //from 则是引入数据源 以及指定数据项
    var doubleSearchList = from item in doubeList 
    ....
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 查询表达式中不会真正发生迭代
    • 当执行查询时,才会迭代 也即是 使用了 foreach 查询关键词时

    四、选择对象

    选择对象其实就是 select item,select 子句生成查询结果并指定每个返回的元素的“形状”或类型。 例如,可以指定结果包含的是整个 Customer 对象、仅一个成员、成员的子集,还是某个基于计算或新对象创建的完全不同的结果类型。 这就牛逼了,意思就是说 满足条件的 数据项 可以对其进行一定的操作再返回

    • 当 select 子句生成除源元素副本以外的内容时,该操作称为投影。(只要不是 from item in xxx select item) 结果只要不是原来的副本就是投影

    示例:选择以 B ,K 开头的字符串并全部转为大写

    List<string> stringList = new List<string>() {"Helan","Linken", "Black", "Brownd", "Kindey" };
    
    IEnumerable<string> stringSearchList = from item in stringList
    									   where item.StartsWith("B") || item.StartsWith("K")
    									   select item.ToUpper();
    
    foreach(var item in stringSearchList)
    {
    	Console.WriteLine(item);
    }
    
    //结果
    BLACK
    BROWND
    KINDEY
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    五、筛选

    筛选其实就是使用一定的条件过滤出我们想要的结果,使用的关键字就是 where ,在上面的很多例子里都使用了where 作为筛选条件。

    • 筛选器查询 仅返回表达式为 true 的元素。
    • 筛选器实际指定要从源序列排除哪些元素。

    那就知道了 where 后面跟一个能计算出为 bool true 的表达式即可
    能返回 true 的表达式就相对灵活了 可以是

    • 逻辑运算符: !|| && > < == !=
    • 函数式
    var queryLondonCustomers = from cust in customers
                               where cust.City == "London"
                               select cust;
                               
    where cust.City == "London" && cust.Name == "Devon"
    
    where cust.City == "London" || cust.City == "Paris"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    一个查询表达式可以包含多个 where 子句,一个子句可以包含多个where子表达式。(不推荐这么用)
    如下,结果都一样,第二个比较费脑子些

    // 数据源
    int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
    
    // 查询表达式
    var queryLowNums2 =
    	from num in numbers
    	where num < 5 && num % 2 == 0
    	select num;
    
    // 执行筛选
    foreach (var s in queryLowNums2)
    {
    Console.Write(s.ToString() + " ");
    }
    Console.WriteLine();
    
    // 查询表达式
    var queryLowNums3 =
    	from num in numbers
    	where num < 5
    	where num % 2 == 0
    	select num;
    
    // 执行筛选
    foreach (var s in queryLowNums3)
    {
    	Console.Write(s.ToString() + " ");
    }
    
    //结果 
    // 4 2 0
    // 4 2 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • where 子句是一种筛选机制。 除了不能是第一个或最后一个位置外,它几乎可以放在查询表达式中的任何位置。 where 子句可以出现在 group 子句的前面或后面,具体取决于时必须在对源元素进行分组之前还是之后来筛选源元素。

    六、排序

    在查询表达式中,orderby 子句可对满足条件的序列或子序列(组)以升序或降序排序。 同时我们可以使用一个个或多个次级排序操作,可以指定多个键来排序。 元素类型的默认比较器执行排序。 默认排序顺序为升序。 还可以指定自定义比较器。
    排序的方式有两种:一种升序,一种降序

    • 升序:从小到大
    • 降序:从大到小
    • 数值类:按照 大小排列
    • 字符串:按照 首字母 A-Z 或者 Z-A排列

    最简单的使用用法之一如下:

    // 待查询类的属性
     public class Customer
    {
    	public string Name{get;set;}
    	public string City{get;set;} 
    }
    
    //数据源
    List <Customer> customers = new List <Customer>(){/*一系列初始化*/};
    
    //查询London 城市的Name, 按照升序排列A-Z排序
    //若 对结果进行从 Z 到 A 的逆序排序,使用 orderby  descending即可
    var queryLondonCustomers3 =
        from cust in customers
        where cust.City == "London"
        orderby cust.Name ascending
        select cust;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    简单排序查询-示例

    // 创建数据源
    string[] fruits = { "cherry", "apple", "blueberry" };
    
    // 查询语句-升序
    IEnumerable<string> sortAscendingQuery =
                from fruit in fruits
                orderby fruit //默认升序
                select fruit;
    
    //  查询语句-降序
    IEnumerable<string> sortDescendingQuery =
                from w in fruits
                orderby w descending
                select w;
    
    // 执行查询
    Console.WriteLine("Ascending:");
    foreach (string s in sortAscendingQuery)
    {
    	Console.WriteLine(s);
    }
    
    // 执行查询
    Console.WriteLine(Environment.NewLine + "Descending:");
    foreach (string s in sortDescendingQuery)
    {
    	Console.WriteLine(s);
    }
    
    //结果
    Ascending:
    apple
    blueberry
    cherry
    
    Descending:
    cherry
    blueberry
    apple
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    除了可以直接排序一次,还可以使用次要排序,次要排序的意思其实就是说,在第一轮排序内部的肯定在同级下面有很多相同的数据,我们还可以对其进一步这个已排序组内再进行一次排序。下面看官网的示例就知道啦

       // 数据源的数据项的具体描述
        public class Student
        {
            public string First { get; set; }
            public string Last { get; set; }
            public int ID { get; set; }
        }
    
    	//产生一个数据集合
        public static List<Student> GetStudents()
        {
            List<Student> students = new List<Student>
            {
               new Student {First="Svetlana", Last="Omelchenko", ID=111},
               new Student {First="Claire", Last="O'Donnell", ID=112},
               new Student {First="Sven", Last="Mortensen", ID=113},
               new Student {First="Cesar", Last="Garcia", ID=114},
               new Student {First="Debra", Last="Garcia", ID=115}
            };
    
            return students;
        }
    
    	//主函数执行
        static void Main(string[] args)
        {
            // 产生数据源
            List<Student> students = GetStudents();
    
            // 创建查询
            IEnumerable<Student> sortedStudents =
                from student in students
                orderby student.Last ascending, student.First ascending 
                //先按照 Last 升序排,在升序组内再安装 First 排序即可
                select student;
    
            // 执行查询
            Console.WriteLine("sortedStudents:");
            foreach (Student student in sortedStudents)
            {
            	Console.WriteLine(student.Last + " " + student.First);
            }
            
            //这里涉及到分组的知识,分组的基本条件是要排序后再分组,
            var sortedGroups =
                from student in students
                orderby student.Last, student.First //忽略了 ascending 关键词
                group student by student.Last[0] into newGroup //分组按照 Last首字母,分组后把分组结果塞到newGroup 
                orderby newGroup.Key //分组的集合再排序一次
                select newGroup;
    
            // 执行查询
            Console.WriteLine(Environment.NewLine + "sortedGroups:");
            foreach (var studentGroup in sortedGroups)
            {
                Console.WriteLine(studentGroup.Key);
                foreach (var student in studentGroup)
                {
                    Console.WriteLine("   {0}, {1}", student.Last, student.First);
                }
            }
        }
        
    
    /* Output:
    sortedStudents:
    Garcia Cesar
    Garcia Debra
    Mortensen Sven
    O'Donnell Claire
    Omelchenko Svetlana
    
    sortedGroups:
    G
       Garcia, Cesar
       Garcia, Debra
    M
       Mortensen, Sven
    O
       O'Donnell, Claire
       Omelchenko, Svetlana
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    七、分组

    分组和数据的基本一致,要使用分组的特性就需要使用group 关键字, 在分组语句中 毫无疑问需要我们指定分组的方式,这个方式一般通过统一的类型,就是键 key。分组的结果就是一个键值对, 例如,我们可指定按 City 对结果进行分组,使来自 London 或 Paris 的所有客户位于单独的组内。

    • 使用 group 子句结束查询时,结果将以列表的形式列出。 列表中的每个元素都是具有 Key 成员的对象,列表中的元素根据该键被分组。 在循环访问生成组序列的查询时,必须使用嵌套 foreach 循环。 外层循环循环访问每个组,内层循环循环访问每个组的成员。
    // queryCustomersByCity 是这种类型: IEnumerable>
      var queryCustomersByCity =
          from cust in customers
          group cust by cust.City;
    
      // customerGroup 类型结构 IGrouping
      foreach (var customerGroup in queryCustomersByCity)
      {
          Console.WriteLine(customerGroup.Key);
          foreach (Customer customer in customerGroup)
          {
              Console.WriteLine("    {0}", customer.Name);
          }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    python电影数据可视化分析系统的设计与实现【附源码】
    制造业数字化系统国产替代如何做?
    jmeter 学习笔记
    【c语言】指针和数组笔试题
    Jetson Xavier NX 与飞控(Pixhawk 4 Mini)实现串口通信
    计算机毕业设计springboot+vue基本微信小程序的校园二手闲置物品交易小程序 uniapp
    我的创作纪念日
    Vue中使组件置顶后悬浮
    GO面试一定要看看这些面试题
    .Net 在容器中操作宿主机
  • 原文地址:https://blog.csdn.net/qq_43680827/article/details/125993542