C# 如何使用 Index 和 Range 简化集合操作
Intro
有的语言数组的索引值是支持负数的,表示从后向前索引,比如:arr[-1]
从C#8开始,C#支持了数组的反向Index,和Range操作,反向Index类似于其他语言中的负索引值,但其实是由编译器帮我们做了一个转换,Range使得我们对数组截取某一部分的操作会非常简单,下面来看一下如何使用吧
Sample
使用^可以从集合的最后开始索引元素,如果从数组的最后开始索引元素,最后一个元素应该是1而不是0如:arr[^1]
使用..可以基于某个数组截取集合中的某一段创建一个新的数组,比如varnewArray=array[1..^1],再来看一下下面的示例吧
int[]someArray=newint[5]{1,2,3,4,5}; intlastElement=someArray[^1];//lastElement=5 lastElement.Dump(); someArray[3..5].Dump(); someArray[1..^1].Dump(); someArray[1..].Dump(); someArray[..^1].Dump(); someArray[..2].Dump();
输出结果如下:
Index
那么它是如何实现的呢,索引值引入了一个新的数据结构System.Index,当你使用^运算符的时候,实际转换成了Index。
Index:
publicreadonlystructIndex:IEquatable{ publicIndex(intvalue,boolfromEnd=false); /// CreateanIndexpointingatfirstelement. publicstaticIndexStart=>newIndex(0); ///CreateanIndexpointingatbeyondlastelement. publicstaticIndexEnd=>newIndex(~0); // //Summary: //Getsavaluethatindicateswhethertheindexisfromthestartortheend. // //Returns: //trueiftheIndexisfromtheend;otherwise,false. publicboolIsFromEnd{get;} // //Summary: //Getstheindexvalue. // //Returns: //Theindexvalue. publicintValue{get;} // //Summary: //CreatesanSystem.Indexfromtheendofacollectionataspecifiedindexposition. // //Parameters: //value: //Theindexvaluefromtheendofacollection. // //Returns: //TheIndexvalue. publicstaticIndexFromEnd(intvalue); // //Summary: //CreateanSystem.Indexfromthespecifiedindexatthestartofacollection. // //Parameters: //value: //Theindexpositionfromthestartofacollection. // //Returns: //TheIndexvalue. publicstaticIndexFromStart(intvalue); // //Summary: //Returnsavaluethatindicateswhetherthecurrentobjectisequaltoanother //System.Indexobject. // //Parameters: //other: //Theobjecttocomparewiththisinstance. // //Returns: //trueifthecurrentIndexobjectisequaltoother;falseotherwise. publicboolEquals(Indexother); // //Summary: //Calculatestheoffsetfromthestartofthecollectionusingthegivencollectionlength. // //Parameters: //length: //ThelengthofthecollectionthattheIndexwillbeusedwith.Mustbeapositivevalue. // //Returns: //Theoffset. publicintGetOffset(intlength); // //Summary: //ConvertsintegernumbertoanIndex. // //Parameters: //value: //Theintegertoconvert. // //Returns: //AnIndexrepresentingtheinteger. publicstaticimplicitoperatorIndex(intvalue); }
如果想要自己自定义的集合支持Index这种从数组最后索引的特性,只需要加一个类型是Index的索引器就可以了,正向索引也是支持的,int会自动隐式转换为Index,除了显示的增加Index索引器之外,还可以隐式支持,实现一个intCount{get;}的属性(属性名叫Length也可以),在实现一个int类型的索引器就可以了
写一个简单的小示例:
privateclassTestCollection { publicIListData{get;init;} publicintCount=>Data.Count; publicintthis[intindex]=>Data[index]; //publicintthis[Indexindex]=>Data[index.GetOffset(Data.Count)]; } vararray=newTestCollection() { Data=new[]{1,2,3} }; Console.WriteLine(array[^1]); Console.WriteLine(array[1]);
Range
Range是在Index的基础上实现的,Range需要两个Index来指定开始和结束
publicreadonlystructRange:IEquatable{ /// RepresenttheinclusivestartindexoftheRange. publicIndexStart{get;} ///RepresenttheexclusiveendindexoftheRange. publicIndexEnd{get;} ///ConstructaRangeobjectusingthestartandendindexes. ///Representtheinclusivestartindexoftherange. /// Representtheexclusiveendindexoftherange. publicRange(Indexstart,Indexend) { Start=start; End=end; } /// CreateaRangeobjectstartingfromstartindextotheendofthecollection. publicstaticRangeStartAt(Indexstart)=>newRange(start,Index.End); ///CreateaRangeobjectstartingfromfirstelementinthecollectiontotheendIndex. publicstaticRangeEndAt(Indexend)=>newRange(Index.Start,end); ///CreateaRangeobjectstartingfromfirstelementtotheend. publicstaticRangeAll=>newRange(Index.Start,Index.End); ///Calculatethestartoffsetandlengthofrangeobjectusingacollectionlength. ///Thelengthofthecollectionthattherangewillbeusedwith.lengthhastobeapositivevalue. /// ///Forperformancereason,wedon'tvalidatetheinputlengthparameteragainstnegativevalues. ///ItisexpectedRangewillbeusedwithcollectionswhichalwayshavenonnegativelength/count. ///Wevalidatetherangeisinsidethelengthscopethough. /// public(intOffset,intLength)GetOffsetAndLength(intlength); }
如何在自己的类中支持Range呢?
一种方式是自己直接实现一个类型是Range的索引器
另外一种方式是隐式实现,在自定义类中添加一个Count属性,然后实现一个Slice方法,Slice方法有两个int类型的参数,第一个参数表示offset,第二个参数表示length
来看下面这个示例吧,还是刚才那个类,我们支持一下Range:
privateclassTestCollection { publicIListData{get;init;} //publicint[]this[Rangerange] //{ //get //{ //varrangeInfo=range.GetOffsetAndLength(Data.Count); //returnData.Skip(rangeInfo.Offset).Take(rangeInfo.Length).ToArray(); //} //} publicintCount=>Data.Count; publicint[]Slice(intstart,intlength) { vararray=newint[length]; for(vari=start;i More
新的操作符(^and..)都只是语法糖,本质上是调用Index、Range
Index并不是支持负数索引,从最后向前索引只是编译器帮我们做了一个转换,转换成从前到后的索引值,借助于它,我们很多取集合最后一个元素的写法就可以大大的简化了,就可以从原来的array[array.Length-1]=>array[^1]
Range在创建某个数组的子序列的时候就非常的方便,newArray=array[1..3],需要注意的是,Range是"左闭右开"的,包含左边界的值,不包含右边界的值
还没使用过Index/Range的快去体验一下吧,用它们优化数组的操作吧~~
以上就是C#如何使用Index和Range简化集合操作的详细内容,更多关于c#使用Index和Range简化集合操作的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。