C# 使用 Index 和 Range 简化集合操作

C# 使用 Index 和 Range 简化集合操作

Intro

有的语言数组的索引值是支持负数的,表示从后向前索引,比如:arr[-1]

从 C# 8 开始,C# 支持了数组的反向 Index,和 Range 操作,反向 Index 类似于其他语言中的负索引值,但其实是由编译器帮我们做了一个转换,Range 使得我们对数组截取某一部分的操作会非常简单,下面来看一下如何使用吧

Sample

使用 ^ 可以从集合的最后开始索引元素,如果从数组的最后开始索引元素,最后一个元素应该是 1 而不是0如:arr[^1]

使用 .. 可以基于某个数组截取集合中的某一段创建一个新的数组,比如 var newArray = array[1..^1],再来看一下下面的示例吧

int[] someArray = new int[5] { 1, 2, 3, 4, 5 };
int lastElement = someArray[^1]; // lastElement = 5
lastElement.Dump();someArray[3..5].Dump();someArray[1..^1].Dump();someArray[1..].Dump();someArray[..^1].Dump();someArray[..2].Dump();

输出结果如下:

output

Index

那么它是如何实现的呢,索引值引入了一个新的数据结构 System.Index,当你使用 ^ 运算符的时候,实际转换成了 Index

Index:

public readonly struct Index : IEquatable<Index>
{public Index(int value, bool fromEnd = false);/// <summary>Create an Index pointing at first element.</summary>public static Index Start => new Index(0);/// <summary>Create an Index pointing at beyond last element.</summary>public static Index End => new Index(~0);//// Summary://     Gets a value that indicates whether the index is from the start or the end.//// Returns://     true if the Index is from the end; otherwise, false.public bool IsFromEnd { get; }//// Summary://     Gets the index value.//// Returns://     The index value.public int Value { get; }//// Summary://     Creates an System.Index from the end of a collection at a specified index position.//// Parameters://   value://     The index value from the end of a collection.//// Returns://     The Index value.public static Index FromEnd(int value);//// Summary://     Create an System.Index from the specified index at the start of a collection.//// Parameters://   value://     The index position from the start of a collection.//// Returns://     The Index value.public static Index FromStart(int value);//// Summary://     Returns a value that indicates whether the current object is equal to another//     System.Index object.//// Parameters://   other://     The object to compare with this instance.//// Returns://     true if the current Index object is equal to other; false otherwise.public bool Equals(Index other);//// Summary://     Calculates the offset from the start of the collection using the given collection length.//// Parameters://   length://     The length of the collection that the Index will be used with. Must be a positive value.//// Returns://     The offset.public int GetOffset(int length);//// Summary://     Converts integer number to an Index.//// Parameters://   value://     The integer to convert.//// Returns://     An Index representing the integer.public static implicit operator Index(int value);
}

如果想要自己自定义的集合支持 Index 这种从数组最后索引的特性,只需要加一个类型是 Index 的索引器就可以了,正向索引也是支持的,int 会自动隐式转换为 Index,除了显示的增加 Index 索引器之外,还可以隐式支持,实现一个 int Count {get;} 的属性(属性名叫 Length 也可以),在实现一个 int 类型的索引器就可以了

写一个简单的小示例:

private class TestCollection
{public IList<int> Data { get; init; }public int Count => Data.Count;public int this[int index] => Data[index];//public int this[Index index] => Data[index.GetOffset(Data.Count)];
}
var array = new TestCollection()
{Data = new[] { 1, 2, 3 }
};
Console.WriteLine(array[^1]);
Console.WriteLine(array[1]);

Range

Range 是在 Index 的基础上实现的,Range 需要两个 Index 来指定开始和结束

public readonly struct Range : IEquatable<Range>
{/// <summary>Represent the inclusive start index of the Range.</summary>public Index Start { get; }/// <summary>Represent the exclusive end index of the Range.</summary>public Index End { get; }/// <summary>Construct a Range object using the start and end indexes.</summary>/// <param name="start">Represent the inclusive start index of the range.</param>/// <param name="end">Represent the exclusive end index of the range.</param>public Range(Index start, Index end){Start = start;End = end;}/// <summary>Create a Range object starting from start index to the end of the collection.</summary>public static Range StartAt(Index start) => new Range(start, Index.End);/// <summary>Create a Range object starting from first element in the collection to the end Index.</summary>public static Range EndAt(Index end) => new Range(Index.Start, end);/// <summary>Create a Range object starting from first element to the end.</summary>public static Range All => new Range(Index.Start, Index.End);/// <summary>Calculate the start offset and length of range object using a collection length.</summary>/// <param name="length">The length of the collection that the range will be used with. length has to be a positive value.</param>/// <remarks>/// For performance reason, we don't validate the input length parameter against negative values./// It is expected Range will be used with collections which always have non negative length/count./// We validate the range is inside the length scope though./// </remarks>public (int Offset, int Length) GetOffsetAndLength(int length);
}

如何在自己的类中支持 Range 呢?

一种方式是自己直接实现一个类型是 Range 的索引器

另外一种方式是隐式实现,在自定义类中添加一个 Count 属性,然后实现一个 Slice 方法,Slice 方法有两个 int 类型的参数,第一个参数表示 offset,第二个参数表示 length

来看下面这个示例吧,还是刚才那个类,我们支持一下 Range

private class TestCollection
{public IList<int> Data { get; init; }//public int[] this[Range range]//{//    get//    {//        var rangeInfo = range.GetOffsetAndLength(Data.Count);//        return Data.Skip(rangeInfo.Offset).Take(rangeInfo.Length).ToArray();//    }//}public int Count => Data.Count;public int[] Slice(int start, int length){var array = new int[length];for (var i = start; i < length && i < Data.Count; i++){array[i] = Data[i];}return array;}
}

More

新的操作符 (^ and ..) 都只是语法糖,本质上是调用 IndexRange

Index 并不是支持负数索引,从最后向前索引只是编译器帮我们做了一个转换,转换成从前到后的索引值,借助于它,我们很多取集合最后一个元素的写法就可以大大的简化了,就可以从原来的 array[array.Length-1] => array[^1]

Range 在创建某个数组的子序列的时候就非常的方便, newArray = array[1..3],需要注意的是,Range 是"左闭右开"的,包含左边界的值,不包含右边界的值

还没使用过 Index/Range 的快去体验一下吧,用它们优化数组的操作吧~~

References

  • https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/ranges-indexes

  • https://docs.microsoft.com/en-us/dotnet/api/system.index?view=net-5.0

  • https://docs.microsoft.com/en-us/dotnet/api/system.range?view=net-5.0

  • https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/ranges

  • https://github.com/dotnet/runtime/blob/master/src/libraries/System.Private.CoreLib/src/System/Index.cs

  • https://github.com/dotnet/runtime/blob/master/src/libraries/System.Private.CoreLib/src/System/Range.cs

  • https://github.com/dotnet/runtime/blob/master/src/libraries/System.Private.CoreLib/src/System/ArraySegment.cs

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

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

相关文章

python 服务端框架_GitHub - edisonlz/fastor: Python服务端开发框架-极易上手,超出你的想象!...

欢迎使用Python 服务端开发框架 FastorFastor是一款专为Python 打造的API与后端管理系统&#xff0c;通过精心的设计与技术实现&#xff0c;集成了大部分稳定开发组件&#xff0c;memcache &#xff0c; redis&#xff0c;tornado&#xff0c;django&#xff0c;mysql 等。特点…

我的小服务器

朋友做了一个工控机的板子&#xff0c;我要了一块来&#xff0c;自己加上了迅驰1.2G CPU&#xff0c;再从笔记本上拆了一个1G内存和老的移动硬盘 30G IDE&#xff0c;就算搭起了一个最简陋的服务器。此外我从破DVD光驱上拆了一块铁皮底板&#xff0c;打了几个洞&#xff0c;把主…

爱心助农|百万斤丑苹果紧急待售!谁能帮这些特困孩子熬过寒冷冬天?

题记&#xff1a;人们在猛兽横行的蛮荒年代&#xff0c;得以从树上回归地面&#xff0c;是人们守望相助的结果&#xff0c;也是人类能繁衍至今的原因在这个什么都讲究颜值的年代有这样一个东西却以“丑”、“但非常好吃”引起了我们的注意它便是山西临猗的冰糖心丑苹果还要一个…

php云点播源码,乐视云直播 点播服务端api

php代码<?php class LeshiController{public $userid ;//用户idpublic $secret ;//私钥public $user_unique ;//用户唯一标识码&#xff0c;由乐视网统一分配并提供 UUIDpublic $zhibo_apiurl http://api.open.letvcloud.com/live/execute;//直播接口地址public $dianb…

微软开源AI诊断工具Error Analysis

喜欢就关注我们吧&#xff01;Error Analysis 使用机器学习技术&#xff0c;助数据科学家更好地了解模型错误模式。在 2020 年 5 月的微软 Build 大会上&#xff0c;微软推出了三个响应式的 AI&#xff08;Responsible AI&#xff0c;RAI&#xff09;工具包&#xff0c;这三个工…

【SDL的编程】VC环境搭建

SDL&#xff08;simple DirectMedia Layer&#xff09;是一个可跨平台的开源库&#xff0c;最近由于自己的兴趣&#xff0c;就把它windosXP下的环境搭建了下。PC&#xff1a;Mircrosoft Windows XP Service Pack3Platform&#xff1a;Mircrosoft Visual C 6.0SourceCode&#x…

php正则匹配标点符号,php 正则匹配包含字母、数字以及下划线,且至少包含2种...

【scikit-learn】scikit-learn的线性回归模型&#xfeff;&#xfeff; 内容概要 怎样使用pandas读入数据 怎样使用seaborn进行数据的可视化 scikit-learn的线性回归模型和用法 线性回归模型的评估測度 特征选择的方法 作为有监督学习,分类问题是预 ...icon图标http://images20…

# 保持最外层获取焦点_大事件!沈阳爱尔白内障焕晶诊疗中心正式启用,两位PanOptix三焦点人工晶体植入患者清晰见证!...

近日&#xff0c;沈阳爱尔眼科医院大东院区白内障焕晶诊疗中心正式投入使用&#xff01;由沈阳爱尔眼科医院大东院区业务院长朱建勋领衔的白内障手术团队始终与国内外一流水准保持同步&#xff0c;开创性引进了爱尔康AcrySof IQ PanOptix 新一代三焦点人工晶状体。中心最先入住…

使用 Tye 辅助开发 k8s 应用竟如此简单(六)

续上篇&#xff0c;这篇我们来进一步探索 Tye 更多的使用方法。本篇我们将进一步研究 Tye 与分布式应用程序运行时 Dapr 如何碰撞出更精彩的火花。巧了&#xff0c;巧了&#xff0c;真是巧了 今天正值 dapr 1.0 发布的日子。如果你暂时还不了解什么是 dapr。那不如通过以下简短…

eval() php,js-eval编码,js-eval解码

实例例子 1在本例中&#xff0c;我们将在几个字符串上运用 eval()&#xff0c;并看看返回的结果&#xff1a;eval("x10;y20;document.write(x*y)")document.write(eval("22"))var x10 document.write(eval(x17))输出&#xff1a;200 4 27例子 2看一下在其他…

李阳疯狂英语300句

1.Absolutely.(用于答话&#xff09;是这样;当然是;正是如此;绝对如此。2.Absolutely impossible!绝对不可能的&#xff01;3.All I have to do is learn English. 我所要做的就是学英语。4.Are you free tomorrow?你明天有空吗?5.Are you married?你结婚了吗&#xff1f;6.…

python函数用于创建对象_Python-创建类并使用函数更改其对象值

有人建议我把这个重新贴出来以便更清楚。上完一节课&#xff0c;剩下的就不上这节课了。欢迎任何指导。我已经得出了这个问题的一部分&#xff0c;在那里我坚持要保持简短。我还附上了我的工作。在下面的工作中&#xff0c;我希望能够创建一个包含一个变量的类。我希望能够更改…

BeetleX.WebFamily针对Web SPA应用的改进

BeetleX.WebFamily1.0在集成vueelementaxios的基础上添加应用页、窗体布局和登陆验证等功能。通过以上功能开发Web SPA应用时只需要编写vue控件和配置菜单即可实现应用开发。使用创建一个.net控制台项目&#xff0c;然后通过Nuget引入BeetleX.WebFamily1.0组件&#xff0c;并在…

php acl rbac,建站常用的用户权限管理模型ACL和RBAC的区别

常用的权限管理模型ACL和RBAC的区别1.ACLACL是最早也是最基本的一种访问控制机制&#xff0c;它的原理非常简单&#xff1a;每一项资源&#xff0c;都配有一个列表&#xff0c;这个列表记录的就是哪些用户可以对这项资源执行CRUD中的那些操作。当系统试图访问这项资源时&#x…

测光

所谓测光其实就是指数码相机根据环境光线系统依靠特定的测量方式而给出的光圈/快门组合的方式。简单的说&#xff0c;也就是对被摄物体的受光情况进行测量。一般来说&#xff0c;测光主要是测定被拍摄对象反射到镜头中的光亮度然后在根据这一亮度给出一定的光圈快门速度组合。而…

python3怎么安装gmpy2_python2/3 模块gmpy2在linux下安装

&#xff01;&#xff01;&#xff01;首先建议在Windows下安装 因为很方便&#xff01;&#xff01;&#xff01;gmpy2是解密RSA时所用脚本的一个模块python下输入 import gmpy2 ,提示 Traceback (most recent call last): File"", line 1, in ImportError: No mod…

华为年终奖,小员工分百万!任正非:钱给多了,不是人才也变成了人才!

华为今年又提前发了巨额年终奖&#xff0c;并公布了新的奖金方案&#xff0c;23级奖金额有近百万&#xff0c;并且宣称“上不封顶、绝不拖欠”&#xff0c;一时间引起热议。任正非签发的内部文件&#xff1a;华为不搞按资排辈&#xff0c;只要做出突出贡献&#xff0c;在新方案…

Redis缓存穿透、缓存雪崩、缓存击穿好好说说

前言 Redis是目前非常流行的缓存数据库啦&#xff0c;其中一个主要作用就是为了避免大量请求直接打到数据库&#xff0c;以此来缓解数据库服务器压力&#xff1b;用上缓存难道就高枕无忧了吗&#xff1f;no,no,no&#xff0c;没有这么完美的技术&#xff0c; 缓存穿透、缓存雪崩…

php字符串赋值给变量,JavaScript-如何将一个PHP字符串安全赋值给Javascript变量(包含引号和换行符的)...

php json_encode输出变量&#xff0c;在js使用(不是赋值)的时候转换成相应的字符串进行操作.注意&#xff1a;因为中文在json_encode会出问题。因此大家写了一个第三方的json_encode;class json {function __construct() {}function encode($array) {$this -> arrayRecursiv…

小计 合计 -统计

create table [tb]([客户编码] varchar(10),[客户名称] varchar(10),[数量] int) insert [tb] select 001,A,2 union all select 001,A,3 union all select 001,A,4 union all select 002,B,1 union all select 002,B,2 --统计 select * from (select * from tb union all s…