c# Linq查询详解

作者:DullFish 时间:2023-05-23 20:43:50 

目录
  • 基本查询

  • 延迟查询属性

  • 类型筛选

  • 复合from子句

  • 多级排序

  • 分组

  • 联合查询-join

  • 合并-zip()

  • 分区(分页)

  • 并行linq

  • 取消长时间运行的并行linq查询

c#提供的ling查询极大的遍历了集合的查询过程,且使用简单方便,非常的有用。

下面将分别用简单的例子说明:ling基本查询、延迟查询属性、类型筛选、复合from字句、多级排序、分组查询、联合查询、合并、分页、聚合操作符、并行linq、取消长时间运行的并行ling查询。

Lambda表达式简介:


/*Lambda表达式:Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数
            表达式位于 => 运算符右侧的 lambda 表达式称为“表达式 lambda”。
            * (input parameters) => expression
            * 示例:*/
             delegate int del(int i);  
             static void Main(string[] args)
             {
                  del myDelegate = x => x * x;  
                  int j = myDelegate(5); //最后j = 25  
              }

基本查询

语句:


var query = from r in listStudents where r.score < 60 orderby r.score descending select r;
//var q2 = listStudents.Where(r => r.score < 60).OrderByDescending(r => r.score).Select(r => r) ;//或使用Lambda表达式

例子:


/// <summary>
       /// 学生结构体
       /// </summary>
       struct Student
       {
           /// <summary>
           /// 姓名
           /// </summary>
           public string name;
           /// <summary>
           /// 年龄
           /// </summary>
           public int age;
           /// <summary>
           /// 班号
           /// </summary>
           public int grade;
           /// <summary>
           /// 分数
           /// </summary>
           public float score;
       }
/// <summary>
       /// linq
       /// 基本查询
       /// </summary>
       static void Linq1()
       {
           #region 构造查询数据
           List<Student> listStudents = new List<Student>();
           Random pRandom = new Random();
           for (int i = 1; i < 50; i++)
           {
               float sc = pRandom.Next(0, 100);
               int age = pRandom.Next(8, 13);
               int gde = pRandom.Next(1, 6);

string name = "";
               switch (pRandom.Next(0, 6))
               {
                   case 1: name = "周xxx"; break;
                   case 2: name = "李xxx"; break;
                   case 3: name = "孙xxx"; break;
                   case 4: name = "钱xxx"; break;
                   default: name = "赵xxx"; break;
               }

Student psdt = new Student();
               psdt.name = name;
               psdt.age = age;
               psdt.grade = gde;
               psdt.score = sc;
               listStudents.Add(psdt);
           }
           #endregion
           //从50个学生中选择出不及格的人员名单并按分数降序排列
           var query = from r in listStudents where r.score < 60 orderby r.score descending select r;
           //var q2 = listStudents.Where(r => r.score < 60).OrderByDescending(r => r.score).Select(r => r) ;//或使用Lambda表达式
           //orderby升序即从小到大,orderby r.score descending降序即从大到小

Console.WriteLine("不及格的人员名单:");
           foreach (Student st in query)
           {
               Console.WriteLine("***************");
               Console.WriteLine("姓名:"+st.name);
               Console.WriteLine("班级:"+st.grade);
               Console.WriteLine("年龄:"+st.age);
               Console.WriteLine("分数:"+st.score);
           }
           Console.ReadKey();
       }

延迟查询属性

linq查询为延迟查询,只需构造一次查询语句,可以多次使用。

例子:


/// <summary>
       /// Linq
       /// 延迟查询
       /// linq查询为延迟查询,只需构造一次查询语句,可以多次使用
       /// </summary>
       static void Linq2()
       {
           #region 构造查询数据
           List<string> lists = new List<string> { "Jack","Pet","Hant","Li","Kkk"};

#endregion
           var query = from r in lists where r.StartsWith("J") select r;
           Console.WriteLine("第一次查询结果:");
           foreach (string st in query)
           {
               Console.WriteLine( st);
           }

Console.WriteLine("第二次查询结果:");
           lists.Add("Jone");
           lists.Add("Jimi");
           lists.Add("Johu");
           foreach (string st in query)
           {
               Console.WriteLine(st);
           }

Console.ReadKey();
           /*
            输出结果:
            * 第一次:Jack
            * 第二次:Jack Jone Jimi Johu
            */
       }

类型筛选

利用OfType方法可以把特定类型数据筛选出来。

例子


/// <summary>
       /// Linq类型筛选-ofType
       /// </summary>
       static void Linq3()
       {
           object[] pList = new object[] { 1,"one",2,"two",3,"three"};
           var query = pList.OfType<string>();
           foreach (var st in query)
           {
               Console.WriteLine(st);
           }
           Console.ReadKey();
           /*
           输出结果:
           * one two three
           */
       }

复合from子句

语句:


var query = from s in listStudents
                       from n in s.name
                       where n == '赵' orderby s.score descending
                       select s.grade + "班-" + s.name + ",分数" + +s.score;
           /*查询出所有姓赵的学生的班级、姓名、分数信息,并按分数由高到低排序*/

例子:


/// <summary>
       /// linq复合from字句
       /// </summary>
       static void Linq4()
       {
           #region 构造查询数据
           List<Student> listStudents = new List<Student>();
           Random pRandom = new Random();
           for (int i = 1; i < 50; i++)
           {
               float sc = pRandom.Next(0, 100);
               int age = pRandom.Next(8, 13);
               int gde = pRandom.Next(1, 6);

string name = "";
               switch (pRandom.Next(0, 6))
               {
                   case 1: name = "周xxx"; break;
                   case 2: name = "李xxx"; break;
                   case 3: name = "孙xxx"; break;
                   case 4: name = "钱xxx"; break;
                   default: name = "赵xxx"; break;
               }

Student psdt = new Student();
               psdt.name = name;
               psdt.age = age;
               psdt.grade = gde;
               psdt.score = sc;
               listStudents.Add(psdt);
           }
           #endregion
           var query = from s in listStudents
                       from n in s.name
                       where n == '赵' orderby s.score descending
                       select s.grade + "班-" + s.name + ",分数" + +s.score;
           /*查询出所有姓赵的学生的班级、姓名、分数信息,并按分数由高到低排序*/
           foreach (var t in query)
           {
               Console.WriteLine(t);
           }
           Console.ReadKey();
       }

多级排序

语句:


//参数越靠前,优先级越高
           //先按score排序,当分数相同时再按grade排序...依次类推
           var query = from s in listStudents orderby s.score, s.grade, s.age, s.name select s;

例子:


/// <summary>
       /// 多级排序
       /// </summary>
       static void Linq5()
       {
           #region 构造查询数据
           List<Student> listStudents = new List<Student>();
           Random pRandom = new Random();
           for (int i = 1; i < 50; i++)
           {
               float sc = pRandom.Next(0, 100);
               int age = pRandom.Next(8, 13);
               int gde = pRandom.Next(1, 6);

string name = "";
               switch (pRandom.Next(0, 6))
               {
                   case 1: name = "周xxx"; break;
                   case 2: name = "李xxx"; break;
                   case 3: name = "孙xxx"; break;
                   case 4: name = "钱xxx"; break;
                   default: name = "赵xxx"; break;
               }

Student psdt = new Student();
               psdt.name = name;
               psdt.age = age;
               psdt.grade = gde;
               psdt.score = sc;
               listStudents.Add(psdt);
           }
           #endregion
           //参数越靠前,优先级越高
           //先按score排序,当分数相同时再按grade排序...依次类推
           var query = from s in listStudents orderby s.score, s.grade, s.age, s.name select s;
           foreach (Student st in query)
           {
               Console.WriteLine("***************");
               Console.WriteLine("姓名:" + st.name);
               Console.WriteLine("班级:" + st.grade);
               Console.WriteLine("年龄:" + st.age);
               Console.WriteLine("分数:" + st.score);
           }
           Console.ReadKey();
       }

分组

语句:


//按国家分组,并选出大于2的组,形成新的集合
           var query = from r in listChampion
                       group r by r.country into g
                       orderby g.Count() descending, g.Key
                       where g.Count() >= 2
                       select
                           new { country = g.Key, count = g.Count() };

例子:


/// <summary>
       /// 分组
       /// </summary>
       static void Linq6()
       {
           List<Champions> listChampion = new List<Champions>();
           listChampion.Add(new Champions() { name = "张**", country = "中国" });
           listChampion.Add(new Champions() { name = "赵**", country = "中国" });
           listChampion.Add(new Champions() { name = "李**", country = "中国" });
            listChampion.Add(new Champions() { name = "李**", country = "中国" });
           listChampion.Add(new Champions() { name = "Peter", country = "美国" });
           listChampion.Add(new Champions() { name = "Hune", country = "美国" });
             listChampion.Add(new Champions() { name = "Hune", country = "美国" });
           listChampion.Add(new Champions() { name = "Jack", country = "俄罗斯" });
             listChampion.Add(new Champions() { name = "Jack", country = "俄罗斯" });
           listChampion.Add(new Champions() { name = "Jimi", country = "英国" });
           //按国家分组,并选出大于2的组,形成新的集合
           var query = from r in listChampion
                       group r by r.country into g
                       orderby g.Count() descending, g.Key
                       where g.Count() >= 2
                       select
                           new { country = g.Key, count = g.Count() };
           foreach (var o in query)
           {
               Console.WriteLine("国家:{0},冠军数:{1}个", o.country, o.count);
           }
           Console.ReadKey();
       }

联合查询-join

语句:


//查询出集合qSt中year等于集合qSc中year的元素并形成新的集合
           var qjoin = from r in qSt
                       join c in qSc
                       on r.year equals c.year
                       select new
                       {
                           Year = r.year,
                           stName = r.name,
                           scName = c.name
                       };

例子:


/// <summary>
       /// 联合查询-join
       /// </summary>
       static void Linq7()
       {
           List<s> pSt = new List<s>();
           pSt.Add(new s() {year=1999,name="xxx" });
           pSt.Add(new s() { year = 2000, name = "xxx" });
           pSt.Add(new s() { year = 2001, name = "xxx" });
           pSt.Add(new s() { year = 2010, name = "xxx" });
           List<school> pSc = new List<school>();
           pSc.Add(new school() { year = 1999, name = "***" });
            pSc.Add(new school() { year = 2001, name = "***" });
           pSc.Add(new school() { year = 2002, name = "***" });
           pSc.Add(new school() { year = 2010, name = "***" });
           pSc.Add(new school() { year = 2012, name = "***" });

var qSt = from r in pSt where r.year >= 2000 select r;
           var qSc = from r in pSc where r.year >= 2000 select r;

//查询出集合qSt中year等于集合qSc中year的元素并形成新的集合
           var qjoin = from r in qSt
                       join c in qSc
                       on r.year equals c.year
                       select new
                       {
                           Year = r.year,
                           stName = r.name,
                           scName = c.name
                       };

foreach (var ite in qjoin)
           {
               Console.WriteLine(ite.Year + " " + ite.scName + " " + ite.stName);
               Console.WriteLine("");
           }
           Console.ReadKey();
       }

合并-zip()

.Net4.0新增,可对两个相关的序列进行合并。

语句:


 /*若合并两项项数不同,则在达到较小集合的末尾时停止*/
           var qZip = qSc.Zip(qSt, (first, second) =>string.Format("Year:{0},Name:{1}.", first.Year,second.Name));//返回值qZip为字符串集合

例子:


/// <summary>
       /// 合并-zip()-.Net4.0新增,可对两个相关的序列进行合并
       /// </summary>
       static void Linq8()
       {
           List<s> pSt = new List<s>();
           pSt.Add(new s() { year = 1999, name = "一xxx" });
           pSt.Add(new s() { year = 2000, name = "二xxx" });
           pSt.Add(new s() { year = 2001, name = "三xxx" });
           pSt.Add(new s() { year = 2010, name = "四xxx" });
           pSt.Add(new s() { year = 2010, name = "五xxx" });
           List<school> pSc = new List<school>();
           pSc.Add(new school() { year = 1999, name = "1***" });
           pSc.Add(new school() { year = 2012, name = "2***" });
           pSc.Add(new school() { year = 2012, name = "3***" });
           pSc.Add(new school() { year = 2012, name = "4***" });
           pSc.Add(new school() { year = 2012, name = "5***" });

var qSt = from r in pSt where r.year >= 2000 orderby r.year select new { Year = r.year, Name = r.name };
           var qSc = from r in pSc where r.year >= 2000 orderby r.year select new { Year = r.year, Name = r.name };
           /*若合并两项项数不同,则在达到较小集合的末尾时停止*/
           var qZip = qSc.Zip(qSt, (first, second) =>string.Format("Year:{0},Name:{1}.", first.Year,second.Name));//返回值qZip为字符串集合

foreach (var ite in qZip)
           {
               Console.WriteLine(ite);
           }
           Console.ReadKey();

}

分区(分页)

通过Take()和Skip()实现只显示部分查询结果。

语句:


//通过skip跳过指定数量的元素,再通过take提取固定长度元素,可实现分页
               var qr = (from r in listStudents orderby r.score descending select r).Skip(i * pageSize).Take(5);
               //var qr2 = listStudents.OrderByDescending(r => r.score).Select(r => r).Skip(i * pageSize).Take(5);//或

例子


/// <summary>
       /// 分区(分页)-通过Take()和Skip()实现只显示部分查询结果
       /// </summary>
       static void Linq9()
       {
           #region 构造查询数据
           List<Student> listStudents = new List<Student>();
           Random pRandom = new Random();
           for (int i = 1; i < 50; i++)
           {
               float sc = pRandom.Next(0, 100);
               int age = pRandom.Next(8, 13);
               int gde = pRandom.Next(1, 6);

string name = "";
               switch (pRandom.Next(0, 6))
               {
                   case 1: name = "周xxx"; break;
                   case 2: name = "李xxx"; break;
                   case 3: name = "孙xxx"; break;
                   case 4: name = "钱xxx"; break;
                   default: name = "赵xxx"; break;
               }

Student psdt = new Student();
               psdt.name = name;
               psdt.age = age;
               psdt.grade = gde;
               psdt.score = sc;
               listStudents.Add(psdt);
           }
           #endregion

int pageSize = 5;
           int numofPage = (int)Math.Ceiling(listStudents.Count /(double)pageSize);

for (int i = 0; i < numofPage; i++)
           {
               Console.WriteLine("第{0}页", i);

//通过skip跳过指定数量的元素,再通过take提取固定长度元素,可实现分页
               var qr = (from r in listStudents orderby r.score descending select r).Skip(i * pageSize).Take(5);
               //var qr2 = listStudents.OrderByDescending(r => r.score).Select(r => r).Skip(i * pageSize).Take(5);//或
               foreach (var ite in qr)
               {
                   Console.WriteLine(ite.name);
                   Console.WriteLine(ite.score);
               }
               Console.WriteLine("");
           }
           Console.ReadKey();
       }

并行linq

并行查询可以分解查询的工作,使其分布在多个线程上。当pc拥有多个cpu时,可以看到并行查询带来的改进效果。并行LINQ适用于大型的集合查询,并拥有一定的优势。使用

System.Collections.Concurrent.Partitioner.Create
可以手动创建分区器。
语法:


var sum2 = (from x2 in data.AsParallel() where x2 > 20 select x2).Sum();//并行查询

//var sum3 = data.AsParallel().Where(x3 => x3 > 20).Sum();//或并行查询(Lambda表达式)

例子:


/// <summary>
       /// 并行linq
       /// </summary>
       static void Linq11()
       {
           Console.WriteLine("开始构造大数组...");
           //构造大数组
           const int count = 100000000;
           var data = new int[count];
           var r = new Random();
           for (int i = 0; i < count; i++)
           {
               data[i] = r.Next(40);
           }
           Console.WriteLine("开始计算...");
           var st = System.DateTime.Now;
           var sum = (from x in data where x > 20 select x).Sum();//常规linq-耗时1.8641s
           var st2 = System.DateTime.Now;
           var sum2 = (from x2 in data.AsParallel() where x2 > 20 select x2).Sum();//并行查询-耗时0.6620s

//var sum3 = data.AsParallel().Where(x3 => x3 > 20).Sum();//或并行查询----x3 => x3 > 20(Lambda表达式)
           var st3 = System.DateTime.Now;

/*Partitioner.Create
            手动创建分区器
            * Create具有多个重载,可依据需求进行分区
            */
           var sum4 = (from c in System.Collections.Concurrent.Partitioner.Create(data, true).AsParallel() where c > 20 select c).Sum();

var dt1 = st2 - st;
           var dt2 = st3 - st2;
           Console.WriteLine("常规linq耗时:{0}s",dt1.TotalSeconds.ToString());
           Console.WriteLine("并行linq耗时:{0}s", dt2.TotalSeconds.ToString());
           Console.ReadKey();
       }

输出结果:

c# Linq查询详解

可以粗鲁的认为并行linq对于大集合的查询是优势比较明显的。

取消长时间运行的并行linq查询

对于并行ling而言,可以设置可以利用System.Threading.CancellationTokenSource设置取消操作。

语法:


//通过.WithCancellation(cts.Token)设置
                   var sum = (from x in data.AsParallel().WithCancellation(cts.Token) where x < 20 select x).Average();

例子:


/// <summary>
       /// 取消长时间运行的并行linq查询
       /// </summary>
       static void Linq12()
       {
           //构造大数组
           const int count = 100000000;
           var data = new int[count];
           var r = new Random();
           for (int i = 0; i < count; i++)
           {
               data[i] = r.Next(40);
           }

var cts = new System.Threading.CancellationTokenSource();

new System.Threading.Thread(() =>
           {
               try
               {
                   //通过.WithCancellation(cts.Token)设置
                   var sum = (from x in data.AsParallel().WithCancellation(cts.Token) where x < 20 select x).Average();
                   Console.WriteLine("sum:{0}", sum);
               }
               catch(OperationCanceledException ex)
               {
                   Console.WriteLine(ex.Message);
               }
           }).Start();

Console.WriteLine("计算开始...");
           Console.WriteLine("取消请按n!");
           var rk = Console.Read();
           if(rk=='n'||rk=='N')
           {
               cts.Cancel();
           }

}

至此,对于LINQ已经有了一个基本的了解。

来源:https://www.cnblogs.com/dullfish/p/6101912.html

标签:c#,linq,查询
0
投稿

猜你喜欢

  • C#中值类型和引用类型的区别深度分析

    2022-07-21 21:29:26
  • 详解java中的static关键字

    2023-09-24 01:44:12
  • @Configuration与@Component作为配置类的区别详解

    2023-03-09 19:50:15
  • git版本回退_动力节点Java学院整理

    2022-06-21 13:26:10
  • C#二进制序列化实例分析

    2022-09-21 01:43:38
  • C# IsDefined的问题

    2022-07-15 10:37:13
  • Android编程基于自定义View实现绚丽的圆形进度条功能示例

    2023-07-24 17:13:26
  • JavaWeb详细讲述Cookie和Session的概念

    2022-03-23 08:39:44
  • Android横竖屏切换及其对应布局加载问题详解

    2023-12-17 20:45:13
  • C#实现创建,删除,查找,配置虚拟目录实例详解

    2022-09-27 06:38:16
  • java 动态 代理的方法总结

    2023-08-25 04:00:33
  • SpringBoot 配置文件总结

    2021-09-06 13:12:57
  • SpringBoot整合WebSocket的客户端和服务端的实现代码

    2023-03-30 04:19:07
  • SpringMVC Interceptor拦截器使用教程

    2022-05-11 02:17:22
  • 解析Tars-Java客户端源码

    2023-04-08 01:18:39
  • Android 实现切圆图作为头像使用实例

    2023-04-29 04:08:08
  • SpringBoot应用线上重启脚本的命令详解

    2022-02-05 18:21:52
  • vscode使用官方C/C++插件无法进行代码格式化问题

    2022-07-13 06:24:47
  • SpringBoot中使用JeecgBoot的Autopoi导出Excel的方法步骤

    2023-03-31 03:38:11
  • Android实现微信朋友圈发本地视频功能

    2021-06-18 07:56:03
  • asp之家 软件编程 m.aspxhome.com