C# Linq用法

C# 中的 LINQ(Language Integrated Query)是一个非常强大的功能,它允许你以声明性方式查询和操作数据集合。LINQ 可以用于各种数据源,如数组、列表、数据库等。

1. 查询操作(Query Operations)

a. 选择(Select)

选择操作允许你从数据源中选择特定的数据。

var numbers = new List<int> { 1, 2, 3, 4, 5 };
var squares = numbers.Select(n => n * n).ToList();
// 结果:squares 包含 {1, 4, 9, 16, 25}
b. 过滤(Where)

过滤操作允许你根据条件选择数据。

var numbers = new List<int> { 1, 2, 3, 4, 5 };
var evenNumbers = numbers.Where(n => n % 2 == 0).ToList();
// 结果:evenNumbers 包含 {2, 4}
c. 排序(OrderBy, OrderByDescending)

排序操作可以对数据进行排序。

var numbers = new List<int> { 5, 1, 4, 2, 3 };
var sortedNumbers = numbers.OrderBy(n => n).ToList();
// 结果:sortedNumbers 包含 {1, 2, 3, 4, 5}var sortedDescNumbers = numbers.OrderByDescending(n => n).ToList();
// 结果:sortedDescNumbers 包含 {5, 4, 3, 2, 1}

2. 聚合操作(Aggregate Operations)

a. 计数(Count)

计数操作可以计算满足条件的元素数量。

var numbers = new List<int> { 1, 2, 3, 4, 5 };
var evenCount = numbers.Count(n => n % 2 == 0);
// 结果:evenCount 为 2
b.求和、求平均值、最大值、最小值
var sum = students.Sum(s => s.Grade);
var average = students.Average(s => s.Age);
var maxGrade = students.Max(s => s.Grade);
var minAge = students.Min(s => s.Age);

3. 集合操作(Set Operations)

a. 去重(Distinct)
var numbers = new List<int> { 1, 2, 2, 3, 4, 4, 5 };
var uniqueNumbers = numbers.Distinct().ToList();
// 结果:uniqueNumbers 包含 {1, 2, 3, 4, 5}
b.交集、并集、差集
var studentsA = new List<Student> { /* ... */ };
var studentsB = new List<Student> { /* ... */ };// 交集
var commonStudents = studentsA.Intersect(studentsB, new StudentComparer()).ToList();// 并集
var allStudents = studentsA.Union(studentsB, new StudentComparer()).ToList();// 差集
var studentsOnlyInA = studentsA.Except(studentsB, new StudentComparer()).ToList();// 注意:这里假设你有一个自定义的StudentComparer类来实现IEqualityComparer<Student>接口。

4. 转换操作(Conversion Operations)

将LINQ查询的结果转换为不同的集合类型,如数组、列表、字典等。

var studentArray = students.ToArray();
var studentDictionary = students.ToDictionary(s => s.Id, s => s.Name);

5. 分组操作(Grouping Operations)

分组操作允许你将集合中的元素按照某个属性或键进行分组。

var students = new List<Student>
{new Student { Name = "张三", Age = 20, Grade = 90 },new Student { Name = "李四", Age = 20, Grade = 85 },new Student { Name = "王五", Age = 21, Grade = 92 },new Student { Name = "赵六", Age = 20, Grade = 88 }
};var groupedByAge = students.GroupBy(s => s.Age).ToList();foreach (var group in groupedByAge)
{Console.WriteLine($"Age: {group.Key}");foreach (var student in group){Console.WriteLine($"Name: {student.Name}, Grade: {student.Grade}");}
}

6. 连接操作(Join Operations)

连接操作允许你根据两个集合之间的某个关系将它们连接起来。

a. 内连接(Inner Join)
var orders = new List<Order>
{new Order { OrderId = 1, CustomerId = 101 },new Order { OrderId = 2, CustomerId = 102 }
};var customers = new List<Customer>
{new Customer { CustomerId = 101, Name = "Alice" },new Customer { CustomerId = 103, Name = "Bob" }
};var query = orders.Join(customers,order => order.CustomerId,customer => customer.CustomerId,(order, customer) => new { OrderId = order.OrderId, CustomerName = customer.Name });foreach (var item in query)
{Console.WriteLine($"Order ID: {item.OrderId}, Customer Name: {item.CustomerName}");
}
b. 左连接(Left Join)

LINQ没有直接的左连接(Left Join)操作,但你可以使用GroupJoin结合DefaultIfEmpty来实现。

var leftJoinQuery = orders.GroupJoin(customers,order => order.CustomerId,customer => customer.CustomerId,(order, customerGroup) => new{OrderId = order.OrderId,CustomerName = customerGroup.DefaultIfEmpty(new Customer { Name = "(No customer)" }).First().Name});foreach (var item in leftJoinQuery)
{Console.WriteLine($"Order ID: {item.OrderId}, Customer Name: {item.CustomerName}");
}
b. 右连接(Right Join)

通过左连接(Left Join)或内连接(Inner Join)加上一些额外的逻辑来实现类似的效果。不过,一个更直观且常用的方法是使用左连接并颠倒数据源的顺序,然后调整结果输出。

为了真正模拟右连接,我们可以考虑将所有来自customers的项都包含在结果中,即使它们没有对应的orders。这可以通过将左连接中的orderscustomers列表交换位置,并在处理结果时确保每个Customer至少出现一次(如果有匹配的Order则显示该Order的ID,否则显示某种占位符)。

var rightJoinQuery = customers.GroupJoin(orders,customer => customer.CustomerId,order => order.CustomerId,(customer, orderGroup) => new{CustomerId = customer.CustomerId,CustomerName = customer.Name,OrderId = orderGroup.Select(o => o.OrderId).DefaultIfEmpty(-1).FirstOrDefault() // 使用-1或其他占位符表示没有匹配的订单}).Select(x => new{OrderId = x.OrderId == -1 ? "(No order)" : x.OrderId.ToString(), // 转换OrderId以更好地显示无订单的情况CustomerName = x.CustomerName});foreach (var item in rightJoinQuery)
{Console.WriteLine($"Order ID: {item.OrderId}, Customer Name: {item.CustomerName}");
}

注意,这里我们使用了-1作为没有订单时的OrderId占位符,并在输出时将其转换为字符串"(No order)"以提高可读性。你也可以根据需求选择其他占位符或逻辑来处理无订单的情况。

7. 分区操作(Partitioning Operations)

分区操作通常指的是将集合分成两个或更多基于某种条件的子集合。不过,直接使用TakeSkip来实现分区可能不完全符合传统意义上的分区(如使用谓词来分区),但这里我们可以用它们来模拟取出集合的前N个元素和剩余的元素。

using System;
using System.Collections.Generic;
using System.Linq;class Student
{public string Name { get; set; }public int Age { get; set; }
}class Program
{static void Main(){List<Student> students = new List<Student>{new Student { Name = "Alice", Age = 20 },new Student { Name = "Bob", Age = 22 },new Student { Name = "Charlie", Age = 21 },new Student { Name = "David", Age = 23 }};// 分区操作:取前两个学生var firstTwoStudents = students.Take(2).ToList();Console.WriteLine("First Two Students:");foreach (var student in firstTwoStudents){Console.WriteLine($"Name: {student.Name}, Age: {student.Age}");}// 分区操作:跳过前两个学生,取剩余学生var remainingStudents = students.Skip(2).ToList();Console.WriteLine("\nRemaining Students:");foreach (var student in remainingStudents){Console.WriteLine($"Name: {student.Name}, Age: {student.Age}");}}
}

8. 分页操作(Paging Operations)

分页操作允许你从一个集合中取出特定页的数据。这通常通过SkipTake方法组合实现,其中Skip方法跳过前N个元素,Take方法取出之后的M个元素。

using System;
using System.Collections.Generic;
using System.Linq;// 假设其他代码与上面相同...class Program
{static void Main(){// ...(假设students列表已定义并初始化)int pageSize = 2; // 每页显示2个学生int pageIndex = 1; // 当前页码,从1开始// 分页操作:取出第1页的数据var pagedResults = students.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();Console.WriteLine($"Page {pageIndex} of Students:");foreach (var student in pagedResults){Console.WriteLine($"Name: {student.Name}, Age: {student.Age}");}// 如果你想查看第2页(示例)pageIndex = 2;pagedResults = students.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();Console.WriteLine($"\nPage {pageIndex} of Students:");foreach (var student in pagedResults){Console.WriteLine($"Name: {student.Name}, Age: {student.Age}");}}
}

在上面的代码中,我们首先定义了一个Student类和一个包含Student对象的List<Student>。然后,我们通过TakeSkip方法实现了分区操作(取前N个和剩余的元素)和分页操作(按页显示数据)。

9. 投影操作(Projection Operations)

投影操作允许你选择集合中的某些属性,并可以创建新的匿名类型或对象。

var studentNames = students.Select(s => new { Name = s.Name, Age = s.Age }).ToList();foreach (var item in studentNames)
{Console.WriteLine($"Name: {item.Name}, Age: {item.Age}");
}

10. 元素操作(Element Operations)

a. FirstOrDefault

获取满足条件的第一个元素,如果没有找到则返回默认值(对于引用类型为null,对于值类型为该类型的默认值)。

var firstStudent = students.FirstOrDefault(s => s.Age > 20);if (firstStudent != null)
{Console.WriteLine($"First student older than 20: {firstStudent.Name}");
}
b. SingleOrDefault

获取满足条件的单个元素,如果没有找到或找到多个元素则抛出异常或返回默认值。

// 假设有一个唯一标识的ID
var specificStudentId = 1;
var specificStudent = students.SingleOrDefault(s => s.Id == specificStudentId);if (specificStudent != null)
{Console.WriteLine($"Found student with ID {specificStudentId}: {specificStudent.Name}");
}
else
{Console.WriteLine($"No student found with ID {specificStudentId}.");
}// 如果集合中存在多个具有相同ID的学生,调用SingleOrDefault将抛出InvalidOperationException
// 为了避免这种情况,你应该确保你的查询条件能够唯一确定一个元素,或者使用FirstOrDefault来处理可能存在的多个匹配项。

在上面的代码中,SingleOrDefault方法用于从students集合中查找具有特定Id的学生。如果找到了一个具有该Id的学生,则将其赋值给specificStudent变量并打印出来。如果没有找到任何具有该Id的学生,则specificStudent将为null,并打印出相应的消息。

然而,如果集合中有多个学生具有相同的Id(这在正常情况下是不应该发生的,因为Id应该是唯一的),调用SingleOrDefault将会抛出一个InvalidOperationException异常。因此,在使用SingleOrDefault时,你应该确保你的查询条件能够唯一确定一个元素。

如果你不确定是否存在多个匹配项,但只想获取第一个匹配项(如果有的话),那么你应该使用FirstOrDefault方法。这样,即使存在多个匹配项,你也只会得到第一个匹配项,而不会抛出异常。如果你需要处理所有匹配项,那么应该使用Where方法来进行筛选,并处理返回的集合。

11. 自定义查询操作符(Custom Query Operators)

LINQ是可扩展的,你可以通过实现IQueryable<T>IEnumerable<T>的扩展方法来创建自定义的查询操作符。

public static class EnumerableExtensions
{public static IEnumerable<TSource> FilterBy<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate){// 这里只是一个简单的示例,实际上它只是重新实现了Where方法return source.Where(predicate);}
}// 使用自定义的FilterBy方法
var filteredStudents = students.FilterBy(s => s.Age > 20);

12. 异步LINQ(Async LINQ)

从.NET Core 3.0开始,引入了IAsyncEnumerable接口,允许你编写异步的LINQ查询,这对于处理大量数据或需要从远程数据源异步加载数据的场景非常有用。

// 假设你有一个返回IAsyncEnumerable<Student>的异步方法
IAsyncEnumerable<Student> GetStudentsAsync()
{// ... 异步加载学生数据yield return new Student { /* ... */ };
}// 使用await foreach循环来异步遍历学生数据
await foreach (var student in GetStudentsAsync())
{Console.WriteLine(student.Name);
}

请注意,并非所有的LINQ操作符都支持异步版本,但你可以通过扩展方法或第三方库来添加对异步LINQ的支持。

13. 延迟执行与立即执行

LINQ查询本身不会立即执行,而是会延迟执行,直到你遍历查询结果或调用需要实际结果的LINQ方法(如ToList(), ToArray(), First(), Single()等)时才会执行。这种延迟执行的行为允许你构建复杂的查询链,而不需要担心中间步骤的性能开销。

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

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

相关文章

【Python与GUI开发】事件处理与打包分发

文章目录 前言 一、高级事件处理 1.自定义事件 2.拖放操作 3.复杂控件的事件处理 二、打包和分发 Tkinter 应用 1.PyInstaller 2.cx_Freeze 3.spec 文件 4.分发注意事项 三、实战示例&#xff1a;文件浏览器 总结 前言 在前面的讨论中&#xff0c;我们深入理解了 T…

Docker基本讲解及演示

Docker安装教程 Docker安装教程 1、Docker介绍 Docker是一个开源的应用容器引擎&#xff0c;允许开发者将应用程序及其依赖项打包成一个轻量级、可移植的容器&#xff0c;然后发布到任何支持 Docker 的环境中运行&#xff0c;无论是开发机、测试机还是生产环境。 Docker基于…

2.设计模式--创建者模式--单例设计模式

2.设计模式–创建者模式–单例设计模式 一个程序整个运行过程中&#xff0c;该实例的对象只被创建一次。 2.1单例设计模式的分类&#xff1a; 饿汉式&#xff1a;类加载时创建单例类的对象 懒汉式&#xff1a;类加载时不创建单例类的对象&#xff0c;第一次访问时创建单例类…

C# lock关键字

C# 中的 lock 关键字是用于同步代码块&#xff0c;确保在同一时间内只有一个线程可以执行该代码块。这是解决多线程环境下资源竞争和数据不一致问题的常用手段之一。 lock 关键字通过锁定一个对象来工作&#xff0c;任何线程在尝试进入被 lock 保护的代码块之前&#xff0c;都…

PCIe驱动开发(3)— 驱动设备文件的创建与操作

PCIe驱动开发&#xff08;3&#xff09;— 驱动设备文件的创建与操作 一、前言 在 Linux 中一切皆为文件&#xff0c;驱动加载成功以后会在“/dev”目录下生成一个相应的文件&#xff0c;应用程序通过对这个名为“/dev/xxx” (xxx 是具体的驱动文件名字)的文件进行相应的操作即…

VAE论文阅读

在网上看到的VAE解释&#xff0c;发现有两种版本&#xff1a; 按照原来论文中的公式纯数学推导&#xff0c;一般都是了解生成问题的人写的&#xff0c;对小白很不友好。按照实操版本的&#xff0c;非常简单易懂&#xff0c;比如苏神的。但是却忽略了论文中的公式推导&#xff…

信创学习笔记(四),信创之数据库DB思维导图

创作不易 只因热爱!! 热衷分享&#xff0c;一起成长! “你的鼓励就是我努力付出的动力” 一. 信创学习回顾 1.信创内容 信创内容思维导图 2.信创之CPU芯片架构 信创之CPU芯片架构思维导图 3.信创之操作系统OS 信创之操作系统OS思维导图 二. 信创之国产数据库DB思维导图 …

什么是带宽限制,如何影响服务器数据传输?

什么是带宽限制? 带宽限制是指网络连接中的数据传输速率上限&#xff0c;通常以每秒传输的数据量(比特或字节)来衡量。例如&#xff0c;一个服务器的带宽限制为100 Mbps&#xff0c;意味着它在理想情况下每秒最多能传输100兆比特的数据。带宽限制由网络服务提供商或数据中心设…

【学习笔记】无人机(UAV)在3GPP系统中的增强支持(四)-无人机系统(UAS)命令与控制(C2)通信用例

引言 本文是3GPP TR 22.829 V17.1.0技术报告&#xff0c;专注于无人机&#xff08;UAV&#xff09;在3GPP系统中的增强支持。文章提出了多个无人机应用场景&#xff0c;分析了相应的能力要求&#xff0c;并建议了新的服务级别要求和关键性能指标&#xff08;KPIs&#xff09;。…

对某根域的一次渗透测试

前言 两个月之前的一个渗透测试项目是基于某网站根域进行渗透测试&#xff0c;发现该项目其实挺好搞的&#xff0c;就纯粹的没有任何防御措施与安全意识所以该项目完成的挺快&#xff0c;但是并没有完成的很好&#xff0c;因为有好几处文件上传没有绕过&#xff08;虽然从一个…

Datawhale AI 夏令营 deepfake图像识别-Task02打卡

数据中存在正负类不平衡问题&#xff0c;目前采用直接每次随机抽取和负类数量相同的正类作为训练集。为了更随机&#xff0c;应该每次都随机选取1:1的正负类&#xff0c;然后加大训练量&#xff1f;目前更换了更好的基础模型&#xff0c;还在跑

Vue3项目基于Axios封装request请求

在 Vue 3 的项目开发中&#xff0c;使用 Axios 进行 HTTP 请求是非常常见的作法&#xff0c;为了更方便开发者更高效的进行代码编写和项目的维护&#xff0c;可以通过再次封装 Axios 来实现。 在本文中&#xff0c;博主将详细指导你如何在自己的 Vue 3 项目中使用 Axios 二次封…

浅谈Git

一&#xff1a;什么是 git git一种开源的分布式版本控制系统&#xff0c;可以有效、高速地处理从很小到非常大的项目版本管理。 下图是 git 的一个工作流程简图 二&#xff1a;什么是 分布/集中式版本控制系统 软件开发过程中&#xff0c;要解决多人协作的问题&#xff0c;需要…

Java之split 方法

方法的工作原理 split 方法首先检查字符串中是否存在指定的分隔符。如果存在&#xff0c;它会在每个分隔符处切割字符串&#xff0c;生成一个新的字符串数组。如果字符串中没有指定的分隔符&#xff0c;或者分隔符是非空字符但在字符串中不存在&#xff0c;则 split 方法会返回…

基于LSTM及其变体的回归预测

1 所用模型 代码中用到了以下模型&#xff1a; 1. LSTM&#xff08;Long Short-Term Memory&#xff09;&#xff1a;长短时记忆网络&#xff0c;是一种特殊的RNN&#xff08;循环神经网络&#xff09;&#xff0c;能够解决传统RNN在处理长序列时出现的梯度消失或爆炸的问题。L…

挂耳式蓝牙耳机什么牌子好?这五款综合表现遥遥领先

为什么这几年开放式耳机受到了越来越多消费者的喜爱&#xff1f;我想是因为它全方位的弥补了入耳式耳机堵塞耳朵、不够安全健康的缺陷&#xff0c;真正做到了安全性与舒适性兼得。那么刚入坑开放式耳机的小白该如何挑选一款品质较高的开放式耳机呢&#xff1f;挂耳式蓝牙耳机什…

微服务中的 “负载均衡策略” 简介

微服务中的负载均衡策略是确保系统高可用性和高性能的关键技术之一。这些策略通过合理地将请求分配给多个服务实例&#xff0c;以实现资源的优化利用和请求的均衡处理。 本文选取以下几种常见的微服务负载均衡策略&#xff0c;并对其功能作简要介绍&#xff1a; 轮询&#xf…

2024年公路水运工程施工企业安全生产管理人员证模拟考试题库及公路水运工程施工企业安全生产管理人员理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年公路水运工程施工企业安全生产管理人员证模拟考试题库及公路水运工程施工企业安全生产管理人员理论考试试题是由安全生产模拟考试一点通提供&#xff0c;公路水运工程施工企业安全生产管理人员证模拟考试题库是…

Qt 实战(7)元对象系统 | 7.3、QMetaObject

文章目录 一、QMetaObject1、什么是QMetaObject&#xff1f;2、QMetaObject提供的主要功能3、如何使用QMetaObject&#xff1f;3.1、获取类的元对象3.2、动态调用方法3.3、读写属性 4、高级应用4.1、动态创建对象4.2、利用QMetaObject进行插件管理 5、总结 前言&#xff1a; 在…

模块化和包管理工具

一&#xff0c;模块化 1.定义 将一个复杂的程序文件依据一定规则&#xff08;规范&#xff09;拆分成多个文件的过程称之为 模块化 其中拆分出的 每个文件就是一个模块 &#xff0c;模块的内部数据是私有的&#xff0c;不过模块可以暴露内部数据以便其他模块使用 2.模块化…