[C#学习笔记]LINQ

视频地址:LINQ入门示例及新手常犯的错误_哔哩哔哩_bilibili

强烈推荐学习C#和WPF的朋友关注此UP,知识点巨多,讲解透彻!

一、基本概念

语言集成查询(Language-Intergrated Query)

常见用途

  • .Net原生集合(List,Array,Dictionary,etc.)
  • SQL数据库(尤其搭配ORM)
  • XML文档
  • JSON文档(Newtonsoft.Json)

常见功能

  • 排序、筛选、选择
  • 分组、聚合、合并
  • 最大值,最小值,求和,求平均,求数量
  • ......

两种形式

  • 查询表达式 query expression
  • 链式表达式 chained expression

例如,现在有个List<int>,内容为0-9,无序排列,需要把其中大于等于4的元素取出并排序

普通写法

var lst = new List<int> {1,3,5,7,9,2,4,6,8,0};var res = new List<int>();
foreach (var n in lst)
{if (n %2 == 0 && n >= 4) res.Add(n);
}res.Sort();
res.Dump();

查询表达式:

var lst = new List<int> {1,3,5,7,9,2,4,6,8,0};var res = from n in lstwhere n % 2== 0 && n >= 4orderby nselect n;res.Dump();

链式表达式:

var lst = new List<int> {1,3,5,7,9,2,4,6,8,0};var res = lst
.Where(n=> n%2 == 0 && n>= 4)
.OrderBy(n=> n);res.Dump();

二、例程

2.1 取两个数组的交集

普通写法

var arr1 = new int[]{1,2,3,4,5,6};
var arr2 = new int[]{4,5,6,7,8,9};var res = new List<int>();
foreach (var n in arr1)
{if (arr2.Contains(n)) res.Add(n);
}res.Dump();

查询表达式

var arr1 = new int[]{1,2,3,4,5,6};
var arr2 = new int[]{4,5,6,7,8,9};var res = from n in arr1 where arr2.Contains(n)select n;res.Dump();

链式表达式

var arr1 = new int[]{1,2,3,4,5,6};
var arr2 = new int[]{4,5,6,7,8,9};var res = arr1.Intersect(arr2);res.Dump();

2.2 统计数组中数字的频率

普通写法

var rnd = new Random(1334);
var arr = Enumerable.Range(0, 200).Select(_ => rnd.Next(20));var dic = new Dictionary<int, int>();
foreach (var n in arr)
{if (dic.TryGetValue(n, out int value)){dic[n] = value +1;}else {dic[n] = 1;}
}dic.Dump();

查询表达式

var rnd = new Random(1334);
var arr = Enumerable.Range(0, 200).Select(_ => rnd.Next(20));var dic = from n in arrgroup n by n into gselect new { g.Key, Count = g.Count() };dic.Dump();

其中

new { Key = g.Key, Count = g.Count() }

为匿名类写法

链式表达式

var rnd = new Random(1334);
var arr = Enumerable.Range(0, 200).Select(_ => rnd.Next(20));var dic = arr.GroupBy(x => x).Select(g => new {Key = g.Key, Count = g.Count()});dic.Dump();

三、重要概念

3.1 延迟执行

LINQ表达式在定义时不会真正的执行,只有在真正消耗时才会执行。

代码一:

var lst = new List<int> { 1, 2, 3, 4, 5 };
var query = lst.Select(x=>x*x);lst.Add(6);
query.Dump();

运行结果为

代码二:

var lst = new List<int>{1,2,3,4,5};Stopwatch watch = new Stopwatch();
watch.Start();
var query = lst.Select(x =>
{Thread.Sleep(500);return x*x;
});watch.Dump();
query.ToList();
watch.Dump();

运行结果

 通过这两个代码可以看出,如果没有对查询表达式进行消耗的操作,表达式并不会真正执行

3.2 消耗

  • 遍历 foreach
  • ToList()、ToArray()、ToDictionary()、
  • Count()、Min()、Max()
  • Take()、First()、Last()

3.3 LINQ并不仅仅是可枚举类型的扩展方法

  • IEnumerable
  • IOrderedEnumerable
  • IQueryable
  • ParallelQuery

四、扩展例程

4.1 展平

将多维数组转为一维形式

查询表达式

var mat = new int[][]{new [] {1,2,3,4},new [] {5,6,7},new [] {8,9,10,11,12}
};var res = from row in matfrom data in rowselect data;res.Dump();	

链式表达式

var mat = new int[][]{new [] {1,2,3,4},new [] {5,6,7},new [] {8,9,10,11,12}
};var res = mat.SelectMany(x=>x);res.Dump();	

运行结果

4.2 笛卡尔积

普通写法

for (int i = 0; i < 5; i++)
{for	(int j = 0; j < 4; j++){for (int k = 0; k < 3; k++){$"{i},{j},{k}".Dump();}}
}

运行结果


查询表达式

var prods = from i in Enumerable.Range(0, 5)from j in Enumerable.Range(0, 4)from k in Enumerable.Range(0, 3)select $"{i},{j},{k}";prods.Dump();

链式表达式

var prods = Enumerable.Range(0, 5).SelectMany(r => Enumerable.Range(0, 4), (l,r)=>(l,r)).SelectMany(r => Enumerable.Range(0, 3), (l,r)=>(l.l, l.r, r)).Select(x=>x.ToString());prods.Dump();

4.3 字母频率

查询表达式

var words = new string[]{"tom", "jerry", "spike", "tyke", "butch", "quacker"};var query = from w in wordsfrom c in wgroup c by c into gselect new {g, Count=g.Count()} into aorderby a.Count descendingselect a;query.Dump();

结果

链式表达式

var words = new string[]{"tom", "jerry", "spike", "tyke", "butch", "quacker"};var query = words.SelectMany(x=>x).GroupBy(x=>x).Select(x => new { x, Count = x.Count() }).OrderByDescending(x => x.Count);query.Dump();

4.4 批量下载文件

普通写法

var urls = new string[]
{"http://www.example.com/pic1.png","http://www.example.com/pic2.png","http://www.example.com/pic3.png"
};$"Tasks start at {DateTime.Now.ToString("HH:mm:ss ffff")}".Dump();
foreach (var url in urls)
{await DownloadAsync(url, url.Split('/').Last());
}
$"Tasks end at {DateTime.Now.ToString("HH:mm:ss ffff")}".Dump();async Task DownloadAsync(string url, string filename)
{await Task.Delay(1000);$"{filename} downloaded at {DateTime.Now.ToString("HH:mm:ss ffff")}.".Dump();
}

输出结果,可以看到3个任务花了3秒

Tasks start at 16:48:19 7820
pic1.png downloaded at 16:48:20 7829.
pic2.png downloaded at 16:48:21 7841.
pic3.png downloaded at 16:48:22 7844.
Tasks end at 16:48:22 7845

改进写法

var urls = new string[]
{"http://www.example.com/pic1.png","http://www.example.com/pic2.png","http://www.example.com/pic3.png"
};var tasks = new List<Task>();
foreach (var url in urls)
{tasks.Add(DownloadAsync(url, url.Split("/").Last()));
}$"Tasks start at {DateTime.Now.ToString("HH:mm:ss ffff")}".Dump();
await Task.WhenAll(tasks);
$"Tasks end at {DateTime.Now.ToString("HH:mm:ss ffff")}".Dump();async Task DownloadAsync(string url, string filename)
{await Task.Delay(1000);$"{filename} downloaded at {DateTime.Now.ToString("HH:mm:ss ffff")}.".Dump();
}

运行结果,可以看到3个任务花了1秒

Tasks start at 16:47:18 1255
pic1.png downloaded at 16:47:19 1259.
pic3.png downloaded at 16:47:19 1259.
pic2.png downloaded at 16:47:19 1259.
Tasks end at 16:47:19 1265

 查询表达式

var urls = new string[]
{"http://www.example.com/pic1.png","http://www.example.com/pic2.png","http://www.example.com/pic3.png"
};var tasks = from url in urlsselect DownloadAsync(url, url.Split("/").Last());$"Tasks start at {DateTime.Now.ToString("HH:mm:ss ffff")}".Dump();
await Task.WhenAll(tasks);
$"Tasks end at {DateTime.Now.ToString("HH:mm:ss ffff")}".Dump();async Task DownloadAsync(string url, string filename)
{await Task.Delay(1000);$"{filename} downloaded at {DateTime.Now.ToString("HH:mm:ss ffff")}.".Dump();
}

链式表达式

var urls = new string[]
{"http://www.example.com/pic1.png","http://www.example.com/pic2.png","http://www.example.com/pic3.png"
};var tasks = urls .Select(url => DownloadAsync(url, url.Split("/").Last()));$"Tasks start at {DateTime.Now.ToString("HH:mm:ss ffff")}".Dump();
await Task.WhenAll(tasks);
$"Tasks end at {DateTime.Now.ToString("HH:mm:ss ffff")}".Dump();async Task DownloadAsync(string url, string filename)
{await Task.Delay(1000);$"{filename} downloaded at {DateTime.Now.ToString("HH:mm:ss ffff")}.".Dump();
}

五、避坑集合

5.1 尽量使用自带方法

5.1.1 First()、Last()

比如说一个集合处理完后,需要得到其第一个元素,使用以下写法

var arr = new List<int>{1,3,5,7,9,2,4,6,8,0};arr.Select(x=>x).ToList()[0].Dump();

虽然也得到了结果,但是多占用了内存,而是应该尽量使用IEnumerable<T>自带的方法

var arr = new List<int>{1,3,5,7,9,2,4,6,8,0};arr.Select(x=>x).First().Dump();

5.1.2 Average()

不要使用Sum+Count方法求平均数:

var arr = new List<int>{1,3,5,7,9,2,4,6,8,0};(arr.Sum()/arr.Count).Dump();

使用自带方法Average

var arr = new List<int>{1,3,5,7,9,2,4,6,8,0};arr.Average().Dump();

5.1.3 Count()、First()、Min()、Max()等方法可以传参

比如查找第一个偶数

使用Where+First

var arr = new List<int>{1,3,5,7,9,2,4,6,8,0};arr.Where(x=>x%2==0).First().Dump();

可以把条件直接翻入First

var arr = new List<int> { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };var res = from x in arrselect x;

5.1.4 Max()和MaxBy()的区别

比如说,查找年龄最大的对象

var people = new List<Person>
{new ("Tom", 18),new ("Jerry", 19),new ("Nason", 20),
};var age = people.Max(x=> x.Age);
var p = people.First(x=>x.Age == age);
p.Dump();record Person(string Name, int Age);

其实使用MaxBy就可简洁实现

var people = new List<Person>
{new ("Tom", 18),new ("Jerry", 19),new ("Nason", 20),
};var p = people.MaxBy(x=>x.Age);
p.Dump();record Person(string Name, int Age);

5.1.5 Default的使用

First和FirstOrDefault,Last和LastOrDefault,等等

比如说以下代码

var people = new List<Person>
{new ("Tom", 18),new ("Jerry", 19),new ("Nason", 20),
};if (people.Any(x=>x.Age >= 21))people.First(x=>x.Age >= 21).Dump();record Person(string Name, int Age);

使用FirstOrDefault后

var people = new List<Person>
{new ("Tom", 18),new ("Jerry", 19),new ("Nason", 20),
};people.FirstOrDefault(x=>x.Age >= 21).Dump();record Person(string Name, int Age);

5.2 注意开销

5.2.1 滥用ToList(),arr.Where().OrderBy().ToList()[0]

非必要不使用ToList,因为会多占用空间

5.2.2 滥用Count(),Count()>0

在判断集合中是否存在符合某个条件的元素时,应该使用Any(),

因为Count()是需要遍历所有元素,Any()是遇到第一个符合条件的就返回(最极端时才会遍历所有元素)

5.2.3 滥用OrderBy(),不适用Sort

OrderBy().ToList()需要重新开辟内存空间,Sort()是在原有集合上排序,不会多增加空间

而且OrderBy(x=>x)使用了lamda表达式,执行时间更长

5.2.4 不知道First()与Single()的区别

First是返回第一个符合条件的元素(可能有多个)

Single是有且只有一个

6. LINQ个人总结

6.1 命名

6.1.1 from

from后面是变量及变量的命名,作用域为当前LINQ语句。

var arr = new List<int> { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
var res = from x in arrselect x;
var res = from x in Enumerable.Range(0, 5)from y in Enumerable.Range(10, 15)from z in Enumerable.Range(20, 25)select new {First = x, Second = y, Third = z} ;res.Dump();

6.1.2 into

from前面是变量,后面是变量的命名,作用域为当前LINQ语句。

var query =from x in Enumerable.Range(0, 5)select new { x, Square = x * x} into yselect y;query.Dump();

6.1.3 let

let后面等号前为变量名,等号后为变量值,作用域为当前LINQ语句。

var query =from x in Enumerable.Range(0, 5)select new { x, Square = x * x} into ylet result = y.Squareselect result;query.Dump();

6.2 结尾

LINQ语句结尾必须要是select

6.3 Join

Join 个操作 - C# | Microsoft Learn

var students = new List<Student>()
{new (){ FirstName = "Bruce", LastName = "Cambell", ID = 10, Year = GradeLevel.FirstYear, DepartmentID = 223},new (){ FirstName = "Cindy", LastName = "Haneline", ID = 11, Year = GradeLevel.SecondYear, DepartmentID = 300},new (){ FirstName = "Andrea", LastName = "Deville", ID = 12, Year = GradeLevel.ThirdYear, DepartmentID = 400},
};var teachers = new List<Teacher>()
{new (){ First = "Anita", Last = "Ryan", ID = 32, City = "NewYork" },new (){ First = "George", Last = "Bunkelman", ID = 44, City = "Washington"},new (){ First = "Andrew", Last = "Carter", ID = 50, City = "LosAngeles"}
};var departments = new List<Department>()
{new (){ Name = "Secretariat", ID = 500, TeacherID = 32},new (){ Name = "General Office", ID = 300, TeacherID = 44},new (){ Name = "Law Committee", ID = 400, TeacherID = 50},
};public enum GradeLevel
{FirstYear = 1,SecondYear,ThirdYear,FourthYear
};public class Student
{public string FirstName { get; init; }public string LastName { get; init; }public int ID { get; init; }public GradeLevel Year { get; init; }public int DepartmentID { get; init; }
}public class Teacher
{public string First { get; init; }public string Last { get; init; }public int ID { get; init; }public string City { get; init; }
}
public class Department
{public string Name { get; init; }	public int ID { get; init; }public int TeacherID { get; init; }
}

6.3.1 Join ... in ... on ... equals ...

基于特定值联接两个序列


var query = from student in studentsjoin department in departments on student.DepartmentID equals department.IDselect new { Name = $"{student.FirstName} {student.LastName}", DepartmentName = department.Name };query.Dump();

6.3.2 join … in … on … equals … into …

基于特定值联接两个序列,并对每个元素的结果匹配项进行分组


IEnumerable<IEnumerable<Student>> studentGroups = from department in departmentsjoin student in students on department.ID equals student.DepartmentID into studentGroupselect studentGroup;
studentGroups.Dump();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/52386.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SEO 分类策略权威指南

如果你在 SEO 领域工作了一段时间&#xff0c;你可能熟悉网站分类法的概念。这是指网站内容的组织方式以及用户找到他们正在寻找的内容的难易程度。 例如&#xff0c;考虑一个专门从事服装的电子商务网站。结构良好的分类可能包括主要类别&#xff0c;例如男装、女装和配饰&am…

【深度学习讲解笔记】第1章-机器学习基础(2)

模型与函数构造 之前讲到&#xff0c;模型是由机器学习决定参数值的函数&#xff0c;通过训练&#xff0c;机器可以找出最好的一组参数使得函数的输出最优。常见的模型有线性模型&#xff0c;指数模型&#xff0c;对数模型等。在线性模型中&#xff0c;w和b是可学习的参数&…

基于SpringBoot的智能制造云平台系统的设计与实现计算机毕设

一、选题背景与意义&#xff08;300字左右&#xff09; 根据工业4.0智能制造生态链中云工厂在实际生产当中的工作流程进行充分调研和整理出来的&#xff0c;描述最终用户在本系统中对于生产订单的处理、排产、以及生产的完整在线处理流程和业务需求的文档。 针对制造业而言&a…

TikTok直播为什么要用独立IP

TikTok直播作为一种受欢迎的社交媒体形式&#xff0c;吸引了越来越多的用户和内容创作者。在进行TikTok直播时&#xff0c;选择使用独立IP地址是一种被广泛推荐的做法。本文将探讨为什么在TikTok直播中更推荐使用独立IP&#xff0c;并解释其优势和应用。 独立IP是指一个唯一的互…

基于CNN卷积神经网络迁移学习的图像识别实现

基于CNN卷积神经网络迁移学习的图像识别实现 基于CNN卷积神经网络迁移学习的图像识别实现写在前面一&#xff0c;原理介绍迁移学习的基本方法1.样本迁移&#xff08;Instance based TL&#xff09;2.特征迁移&#xff08;Feature based TL&#xff09;3.模型迁移&#xff08;Pa…

C++(一)----C++基础

1.C的发展史 C语言诞生后&#xff0c;很快普及使用&#xff0c;但是随着编程规模增大且越来越复杂&#xff0c;并且需要高度的抽象和建模时&#xff0c;C语言的诸多短板便表现了出来&#xff0c;为了解决软件危机&#xff0c;上世纪八十年代&#xff0c;计算机界提出了oop&…

如何理解有效值电流?电流的均方根值

电流的有效值就是电流的均方根。 有效值电流定义&#xff1a;将一直流电与一交流电分别通过相同阻值的电阻&#xff0c;如果相同时间内两电流通过电阻产生的热量相同&#xff0c;就说这一直流电的电流值是这一交流电的有效值。 如果说电流就是直流电&#xff0c;那么电流的有效…

Flutter MacOS 去掉窗口导航栏

操作步骤 用xcode打开Flutter项目&#xff0c;点击Runner——>Runner——>Resources——>MainMenu 点击APP_NAME&#xff0c;在右侧勾选窗口选项来控制是否有窗口或者关闭缩小按钮。我这里并没有取消勾选Show Title Bar&#xff0c;因为当我取消勾选后&#xff0c;窗…

已经存在的项目如何变成git的一个repository

已经存在的项目如何被git管理 背景&#xff1a; 有一套代码很敏感&#xff0c;可能动不动就要不能正常工作(硬件开发常事)&#xff0c;那改动一下下就要有个记录&#xff0c;就决定用git管理 已经有了服务里里docker里运行的gitbucket,已经有了开发用的电脑上的git客户端&…

【Python基础】Python函数

本文收录于 《Python编程入门》专栏&#xff0c;从零基础开始&#xff0c;分享一些Python编程基础知识&#xff0c;欢迎关注&#xff0c;谢谢&#xff01; 文章目录 一、前言二、函数的定义与调用三、函数参数3.1 位置参数3.2 默认参数3.3 可变数量参数&#xff08;或不定长参数…

【项目】云备份

云备份 云备份概述框架 功能演示服务端客户端 公共模块文件操作模块目录操作模块 服务端模块功能划分功能细分模块数据管理热点管理 客户端模块功能划分功能细分模块数据管理目录检查文件备份 云备份 概述 自动将本地计算机上指定文件夹中需要备份的文件上传备份到服务器中。…

【Visual Studio 报错】vs 在使用二进制写入文件时弹窗报错:使用简体中文 gb2312 编码加载文件

如以下报错 解决办法 解决方法&#xff1a;文件->高级保存选项->将文件编码形式改为“UTF-8带签名” 若找不到高级保存选项&#xff0c;可以跟着下面路径把该选项调出来 &#xff1a;工具->自定义->命令->菜单栏中改成文件->预览右边点添加命令->类别中…

【C++ Primer Plus习题】14.1

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream> #include "wine.h" …

传知代码-机器情绪及抑郁症算法(四)!(论文复现)

代码以及视频讲解 本文所涉及所有资源均在传知代码平台可获取 计算机来理解你的情绪&#xff1a;情感计算的发展 近年来&#xff0c;多模态情感分析&#xff08;MSA&#xff09;受到越来越多的关注&#xff0c;多模态情感分析是一个综合了视觉、听觉等语言和非语言信息的重要…

Parsec问题解决方案

Parsec目前就是被墙了&#xff0c;有解决方案但治标不治本&#xff0c;如果想稳定串流建议是更换稳定的串流软件&#xff0c;以下是一些解决方案 方案一&#xff1a;在%appdata%/Parsec/config.txt中&#xff0c;添加代理 app_proxy_address 127.0.0.1 app_proxy_scheme http…

Qt篇——Qt在msvc编译下提示“C2001:常量中有换行符“的错误

在pro文件中添加以下配置即可&#xff1a; msvc{QMAKE_CFLAGS /utf-8QMAKE_CXXFLAGS /utf-8 }

双指针(7)_单调性_三数之和

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 双指针(7)_单调性_三数之和 收录于专栏【经典算法练习】 本专栏旨在分享学习C的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1. 题目…

Redis 常用命令总结

文章目录 目录 文章目录 1 . 前置内容 1.1 基本全局命令 KEYS EXISTS ​编辑 DEL EXPIRE TTL TYPE 1.2 数据结构和内部编码 2. String类型 SET GET MGET MSET SETNX INCR INCRBY DECR DECYBY INCRBYFLOAT 命令小结 内部编码 3 . Hash 哈希类型 HSET …

gpt4最新保姆级教程

如何使用 WildCard 服务注册 Claude3 随着 Claude3 的震撼发布&#xff0c;最强 AI 模型的桂冠已不再由 GPT-4 独揽。Claude3 推出了三个备受瞩目的模型&#xff1a;Claude 3 Haiku、Claude 3 Sonnet 以及 Claude 3 Opus&#xff0c;每个模型都展现了卓越的性能与特色。其中&a…

数据结构基本知识

一、什么是数据结构 1.1、组织存储数据 ---------》内存&#xff08;存储&#xff09; 1.2、研究目的 如何存储数据&#xff08;变量&#xff0c;数组....)程序数据结构算法 1.3、常见保存数据的方法 数组&#xff1a;保存自己的数据指针&#xff1a;是间接访问已经存在的…