当前位置: 首页 > news >正文

C# Linq源码分析之Take (三)

概要

本文在前两篇Take源码分析的基础上,着重分析Range参数中有倒数的情况,即分析TakeRangeFromEndIterator的源码实现。

源码及分析

TakeRangeFromEndIterator方法用于处理Range中的开始和结束索引存在倒数的情况。该方法位于Take.cs文件中。通过yield return/break的方式管理迭代过程。

TakeRangeFromEndIterator方法从整体上分为两部分,一部分是TryGetNonEnumeratedCount为真的情况,即souce实现了ICollection接口的情况;另一部分是souce没有实现ICollection接口,TryGetNonEnumeratedCount返回为False的情况。

 private static IEnumerable<TSource> TakeRangeFromEndIterator<TSource>(IEnumerable<TSource> source, bool isStartIndexFromEnd, int startIndex, bool isEndIndexFromEnd, int endIndex)
{if (source.TryGetNonEnumeratedCount(out int count)){startIndex = CalculateStartIndex(isStartIndexFromEnd, startIndex, count);endIndex = CalculateEndIndex(isEndIndexFromEnd, endIndex, count);if (startIndex < endIndex){foreach (TSource element in TakeRangeIterator(source, startIndex, endIndex)){yield return element;}}yield break;}static int CalculateStartIndex(bool isStartIndexFromEnd, int startIndex, int count) =>Math.Max(0, isStartIndexFromEnd ? count - startIndex : startIndex);static int CalculateEndIndex(bool isEndIndexFromEnd, int endIndex, int count) =>Math.Min(count, isEndIndexFromEnd ? count - endIndex : endIndex);
}
  1. 该函数有4个参数,开始索引是否倒数,开始索引值,结束索引是否为倒数,结束索引值;
  2. 如果source实现了ICollection接口,可以在不遍历souce序列的情况下,直接获取序列长度,则TryGetNonEnumeratedCount返回为True;
  3. 调用CalculateStartIndex和CalculateEndIndex内联方法,获取正数的索引值,假设Range是 ^3… ^1,元素共10个,则转换完成后是7…9,即从第7个取到第9个;
  4. 在开始索引值小于结束索引值的前提下,调TakeRangeIterator方法,按照普通正数Range的方法进行处理,并将结果以状态机的形式按照yield return/break方式返回。具体详见 C# Linq源码分析之Take (二)

注意在TryGetNonEnumeratedCount返回为True的情况下,因为可以直接取到序列的元素个数,不需要进行逐个迭代和累加。因此才可以将倒数的Range转换成正数的Range。对于无法获取序列元素的情况,我们看下面的代码分析。

在开始索引是倒数的情况下,进行如下处理,此时假设我们有如下序列,我们的Range是 ^3 … ^1,但是不知道序列内元素个数。
在这里插入图片描述

 Queue<TSource> queue;if (isStartIndexFromEnd){// TakeLast compat: enumerator should be disposed before yielding the first element.using (IEnumerator<TSource> e = source.GetEnumerator()){if (!e.MoveNext()){yield break;}queue = new Queue<TSource>();queue.Enqueue(e.Current);count = 1;while (e.MoveNext()){if (count < startIndex){queue.Enqueue(e.Current);++count;}else{do{queue.Dequeue();queue.Enqueue(e.Current);checked { ++count; }} while (e.MoveNext());break;}}Debug.Assert(queue.Count == Math.Min(count, startIndex));}startIndex = CalculateStartIndex(isStartIndexFromEnd: true, startIndex, count);endIndex = CalculateEndIndex(isEndIndexFromEnd, endIndex, count);Debug.Assert(endIndex - startIndex <= queue.Count);for (int rangeIndex = startIndex; rangeIndex < endIndex; rangeIndex++){yield return queue.Dequeue();}}
  1. 获取souce的迭代器e;
  2. 如果取一个元素失败,证明Range中指定的范围在实际序列中根本取不到,则通过yield break关闭状态机;
  3. 定义缓冲队列queue,将“A”放入队列,元素个数初始值设置为1;
  4. 迭代开始,count < startIndex在元素个数累加器小于启始索引的情况下,每次队列增加一个元素,直到count等于3,此时队列元素是"A", “B”, “C”;
  5. 然后每次删除队首元素,再添加新的元素到队尾,当遍历完整个source序列后,队列元素是“G”, “H”, “I”,此种方法遍历,算法只需要启始索引值,结束索引值完全忽略;
  6. 根据迭代中获取的元素个数count,计算出正数的开始和结束索引,本例应该是6…8;
  7. 将缓冲队列queue按照状态机的形式,通过yield return方式返回;因为rangeIndex < endIndex;,所以最后的返回值是“G”, “H”没有“I”,只会取到结束索引对应元素的前一个元素。

在开始索引不是倒数的情况下, 进行如下处理,此时假设我们有如下序列,我们的Range是 3 … ^2,此时我们并不清楚集合内元素的个数。

请注意在现有的情况下,如果开始索引是正数,结尾索引一定是倒数的。如果结尾索引是正数,更加之前的代码分析,只会进入C# Linq源码分析之Take (二)所介绍的TakeRangeIterator方法。

假设我们使用的数据如下:

在这里插入图片描述

 else{Debug.Assert(!isStartIndexFromEnd && isEndIndexFromEnd);// SkipLast compat: the enumerator should be disposed at the end of the enumeration.using IEnumerator<TSource> e = source.GetEnumerator();count = 0;while (count < startIndex && e.MoveNext()){++count;}if (count == startIndex){queue = new Queue<TSource>();while (e.MoveNext()){if (queue.Count == endIndex){do{queue.Enqueue(e.Current);yield return queue.Dequeue();} while (e.MoveNext());break;}else{queue.Enqueue(e.Current);}}}}
  1. 定义迭代器e 和 集合内初始元素个数计数器设置为0;
  2. 在初始化操作后,count是3,迭代器指向元素C;
  3. 如果count等于 startIndex,证明Range中的取值在下面的序列中可以取到。如果不等,则返回空;
    在这里插入图片描述
  4. 因为是倒数第2个,所以endIndex的数值是2,
  5. D和E进入缓冲队列;
  6. 因为缓冲队列中的长度必须和endIndex相等,队列每进入一个元素到队尾,然后删除队首元素并按照yield return的状态机方式返回。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    最后将所有需要的元素返回。上面算法并不需要直到序列内元素的个数。

相关文章:

C# Linq源码分析之Take (三)

概要 本文在前两篇Take源码分析的基础上&#xff0c;着重分析Range参数中有倒数的情况&#xff0c;即分析TakeRangeFromEndIterator的源码实现。 源码及分析 TakeRangeFromEndIterator方法用于处理Range中的开始和结束索引存在倒数的情况。该方法位于Take.cs文件中。通过yie…...

Linux journalctl命令详解(journalctl指令)(systemd服务默认日志管理工具)

文章目录 Linux Journalctl命令详解1. Journalctl简介2. Journalctl基础使用3. 过滤日志条目4. 时间戳和日志轮转5. 高级应用6. journalctl --help指令文档英文中文 注意事项journal日志不会将程序输出的空行显示&#xff0c;日志会被压缩得满满当当。journal日志不会自动持久化…...

学习内容--

C后台开发_c做后台_人面桃花相映红的博客-CSDN博客 C/C后端开发学习路线总结&#xff08;附带实习学习经历分享&#xff09;_c后端开发需要学什么_Linux后台开发狮的博客-CSDN博客 学到什么程度才可以面试大厂&#xff1f;c/c后台开发进阶指南 后端开发&#xff08;超全&…...

Stable Diffusion:使用自己的数据集微调训练LoRA模型

Stable Diffusion&#xff1a;使用自己的数据集微调训练LoRA模型 前言前提条件相关介绍微调训练LoRA模型下载kohya_ss项目安装kohya_ss项目运行kohya_ss项目准备数据集生成关键词模型参数设置预训练模型设置文件夹设置训练参数设置 开始训练LoRA模型TensorBoard查看训练情况 测…...

软考高级系统架构设计师系列之:论文典型试题写作要点和写作素材总结系列文章一

软考高级系统架构设计师系列之:论文典型试题写作要点和写作素材总结系列文章一 一、论软件体系结构风格及其应用1.论文题目2.写作要点和写作素材二、论开放系统应用的互操作性技术1.论文题目2.写作要点和写作素材三、论多层分布结构系统的开发1.论文题目2.写作要点和写作素材四…...

06 mysql all查询 和 主键查询 和 非索引列查询

前言 本文主要调试一下 mysql 的如下两种查询语句 我们也来深入的看一下, 究竟如下两个普通的查询, mysql 做了什么事情 1. select * from user where id 991; 2. select * from user; 3. select * from user where name jerry991; 环境介绍 测试表 user schema 如下…...

黑马点评-项目集成git及redis实现短信验证码登录

目录 IDEA集成git 传统session存在的问题 redis方案 业务流程 选用的数据结构 整体访问流程 发送短信验证码 获取校验验证码 配置登录拦截器 拦截器注册配置类 拦截器 用户状态刷新问题 刷新问题解决方案 IDEA集成git 远程仓库采用码云&#xff0c;创建好仓库&…...

mac苹果电脑怎么运行Windows软件?怎么安装Win虚拟机?

近年来&#xff0c;苹果电脑的用户群体不断扩大&#xff0c;许多用户对于苹果电脑是否可以运行Windows软件产生了疑问。苹果电脑和Windows操作系统有着明显的区别&#xff0c;是否能够在苹果电脑上运行Windows软件。下面我们就来看苹果电脑可以运行Windows软件吗&#xff0c;苹…...

Jmeter对websocket进行测试

JMeterWebSocketSampler-1.0.2-SNAPSHOT.jar下载 公司使用websocket比较奇怪&#xff0c;需要带认证信息进行长连接&#xff0c;通过websocket插件是请求失败&#xff0c;如下图&#xff0c;后面通过代码实现随再打包jar包完成websocket测试 本地实现代码如下&#xff1a; pa…...

从2023年世界机器人大会发现机器人新趋势

机器人零部件为何成2023年世界机器人大会关注热门&#xff1f; 在原先&#xff0c;机器人的三大核心零部件是控制系统中的控制器、驱动系统中的伺服电机和机械系统中的精密减速器。如今&#xff0c;机器人的主体框架结构已经落实&#xff0c;更多机器人已经开始深入到各类场景中…...

Kafka单节点部署

&#x1f388; 作者&#xff1a;互联网-小啊宇 &#x1f388; 简介&#xff1a; CSDN 运维领域创作者、阿里云专家博主。目前从事 Kubernetes运维相关工作&#xff0c;擅长Linux系统运维、开源监控软件维护、Kubernetes容器技术、CI/CD持续集成、自动化运维、开源软件部署维护…...

生成式AI和大语言模型 Generative AI LLMs

在“使用大型语言模型(LLMs)的生成性AI”中&#xff0c;您将学习生成性AI的基本工作原理&#xff0c;以及如何在实际应用中部署它。 通过参加这门课程&#xff0c;您将学会&#xff1a; 深入了解生成性AI&#xff0c;描述基于LLM的典型生成性AI生命周期中的关键步骤&#xff…...

Obsidian 入门使用手册

文章目录 一、Obsidian 入门1.1 什么是 Obsidian1.2 安装 Obsidian 二、Obsidian 配置2.1 创建第一个笔记2.2 设置界面语言使用中文2.3 主题 三、小结 一、Obsidian 入门 1.1 什么是 Obsidian Obsidian 是一款基于 Markdown 语法编辑的笔记软件。与传统的 Markdown 软件不同的…...

GuLi商城-前端基础Vue指令-单向绑定双向绑定

什么是指令? 指令 (Directives) 是带有 v- 前缀的特殊特性。 指令特性的预期值是:单个 JavaScript 表达式。 指令的职责是&#xff0c;当表达式的值改变时&#xff0c;将其产生的连带影响&#xff0c;响应式地作用于DOM 例如我们在入门案例中的 v-on&#xff0c;代表绑定事…...

前端(十三)——JavaScript 闭包的奥秘与高级用法探索

&#x1f636;博主&#xff1a;小猫娃来啦 &#x1f636;文章核心&#xff1a;深入理解 JavaScript 中的闭包 文章目录 不理解闭包&#xff1f;这玩意很难&#xff1f;闭包的定义与原理闭包是什么创建一个闭包 闭包的应用场景闭包与作用域闭包与作用域之间的关系全局作用域、函…...

面试-快速学习计算机网络-UDP/TCP

1. OSI四层和七层映射 区别&#xff1a; 应用层&#xff0c;表示层&#xff0c;会话层合并为了应用层数据链路层和物理层合并为了网络接口层 2. TCP和UDP的区别&#xff1f; 总结&#xff1a; 1 . TCP 向上层提供面向连接的可靠服务 &#xff0c;UDP 向上层提供无连接不可靠服…...

爱校对如何帮助企业和博客主提高在线可见性?

在数字化时代&#xff0c;内容质量已经成为增强在线曝光率的关键因素。企业和博客主经常面临挑战&#xff0c;如何制作高质量、无误的内容以吸引更多的在线用户。此文将详细分析“爱校对”如何帮助用户优化内容&#xff0c;从而提高在线可见性。 1.互联网内容的挑战 搜索引擎…...

MATLAB中xlsread函数用法

目录 语法 说明 示例 将工作表读取到数值矩阵 读取元胞的范围 读取列 请求数值、文本和原始数据 对工作表执行函数 请求自定义输出 局限性 xlsread函数的功能是读取Microsoft Excel 电子表格文件 语法 num xlsread(filename) num xlsread(filename,sheet) num x…...

Prisma.js:JavaScript中的基于代码的ORM

​Prisma是一种流行的用于服务器端JavaScript和TypeScript的数据映射层&#xff08;ORM&#xff09;。它的核心目的是简化和自动化数据在存储和应用程序代码之间的传输方式。Prisma支持各种数据存储&#xff0c;并为数据持久化提供了一个强大而灵活的抽象层。通过这个基于代码的…...

解决问题:在cocos create中如何从b文件调用到a文件里用CC.resource.load动态加载的图集

目录 1.在a文件中定义一个公共的变量存储动态加载的图集 2.在a.js中添加一个静态方法&#xff0c;返回动态加载的图集 3.在b.js中使用a.js中定义的静态方法获取图集&#xff0c;并使用它 假设a文件中用CC.resource.load动态加载了一张图集&#xff0c;b文件需要使用这张图集&am…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

基于matlab策略迭代和值迭代法的动态规划

经典的基于策略迭代和值迭代法的动态规划matlab代码&#xff0c;实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

接口自动化测试:HttpRunner基础

相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具&#xff0c;支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议&#xff0c;涵盖接口测试、性能测试、数字体验监测等测试类型…...

Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换

目录 关键点 技术实现1 技术实现2 摘要&#xff1a; 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式&#xff08;自动驾驶、人工驾驶、远程驾驶、主动安全&#xff09;&#xff0c;并通过实时消息推送更新车…...

MySQL:分区的基本使用

目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区&#xff08;Partitioning&#xff09;是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分&#xff08;分区&#xff09;可以独立存储、管理和优化&#xff0c;…...