详解c#索引(Index)和范围(Range)

范围和索引为访问序列中的单个元素或范围提供了简洁的语法。

在本教程中,你将了解:

  • 对某个序列中的范围使用该语法。
  • 了解每个序列开头和末尾的设计决策。
  • 了解 Index 和 Range 类型的应用场景。

对索引和范围的语言支持

此语言支持依赖于两个新类型和两个新运算符:

  • System.Index 表示一个序列索引。
  • 来自末尾运算符 ^ 的索引,指定一个索引与序列末尾相关。
  • System.Range 表示序列的子范围。
  • 范围运算符 ..,用于指定范围的开始和末尾,就像操作数一样。

让我们从索引规则开始。 请考虑数组 sequence0 索引与 sequence[0] 相同。 ^0 索引与 sequence[sequence.Length] 相同。 表达式 sequence[^0] 不会引发异常,就像 sequence[sequence.Length] 一样。 对于任何数字 n,索引 ^nsequence[sequence.Length - n] 相同。

string[] words = new string[]
{
        // index from start  index from end
  "The",   // 0          ^9
  "quick",  // 1          ^8
  "brown",  // 2          ^7
  "fox",   // 3          ^6
  "jumped",  // 4          ^5
  "over",   // 5          ^4
  "the",   // 6          ^3
  "lazy",   // 7          ^2
  "dog"    // 8          ^1
};       // 9 (or words.Length) ^0

可以使用 ^1 索引检索最后一个词。 在初始化下面添加以下代码:

Console.WriteLine($"The last word is {words[^1]}");

范围指定范围的开始和末尾。 范围是排除的,也就是说“末尾”不包含在范围内。 范围 [0..^0] 表示整个范围,就像 [0..sequence.Length] 表示整个范围。
以下代码创建了一个包含单词“quick”、“brown”和“fox”的子范围。 它包括 words[1] 到 words[3]。 元素 words[4] 不在该范围内。 将以下代码添加到同一方法中。 将其复制并粘贴到交互式窗口的底部。

string[] quickBrownFox = words[1..4];
foreach (var word in quickBrownFox)
  Console.Write($"< {word} >");
Console.WriteLine();

以下代码使用“lazy”和“dog”返回范围。 它包括 words[^2]words[^1]。 结束索引 words[^0] 不包括在内。 同样添加以下代码:

string[] lazyDog = words[^2..^0];
foreach (var word in lazyDog)
  Console.Write($"< {word} >");
Console.WriteLine();

下面的示例为开始和/或结束创建了开放范围:

string[] allWords = words[..]; // contains "The" through "dog".
string[] firstPhrase = words[..4]; // contains "The" through "fox"
string[] lastPhrase = words[6..]; // contains "the, "lazy" and "dog"
foreach (var word in allWords)
  Console.Write($"< {word} >");
Console.WriteLine();
foreach (var word in firstPhrase)
  Console.Write($"< {word} >");
Console.WriteLine();
foreach (var word in lastPhrase)
  Console.Write($"< {word} >");
Console.WriteLine();

还可以将范围或索引声明为变量。 然后可以在 [ 和 ] 字符中使用该变量:

Index the = ^3;
Console.WriteLine(words[the]);
Range phrase = 1..4;
string[] text = words[phrase];
foreach (var word in text)
  Console.Write($"< {word} >");
Console.WriteLine();

下面的示例展示了使用这些选项的多种原因。 请修改 x、y 和 z 以尝试不同的组合。 在进行实验时,请使用 x 小于 y且 y 小于 z 的有效组合值。 在新方法中添加以下代码。 尝试不同的组合:

int[] numbers = Enumerable.Range(0, 100).ToArray();
int x = 12;
int y = 25;
int z = 36;

Console.WriteLine($"{numbers[^x]} is the same as {numbers[numbers.Length - x]}");
Console.WriteLine($"{numbers[x..y].Length} is the same as {y - x}");

Console.WriteLine("numbers[x..y] and numbers[y..z] are consecutive and disjoint:");
Span<int> x_y = numbers[x..y];
Span<int> y_z = numbers[y..z];
Console.WriteLine($"\tnumbers[x..y] is {x_y[0]} through {x_y[^1]}, numbers[y..z] is {y_z[0]} through {y_z[^1]}");

Console.WriteLine("numbers[x..^x] removes x elements at each end:");
Span<int> x_x = numbers[x..^x];
Console.WriteLine($"\tnumbers[x..^x] starts with {x_x[0]} and ends with {x_x[^1]}");

Console.WriteLine("numbers[..x] means numbers[0..x] and numbers[x..] means numbers[x..^0]");
Span<int> start_x = numbers[..x];
Span<int> zero_x = numbers[0..x];
Console.WriteLine($"\t{start_x[0]}..{start_x[^1]} is the same as {zero_x[0]}..{zero_x[^1]}");
Span<int> z_end = numbers[z..];
Span<int> z_zero = numbers[z..^0];
Console.WriteLine($"\t{z_end[0]}..{z_end[^1]} is the same as {z_zero[0]}..{z_zero[^1]}");

索引和范围的类型支持

索引和范围提供清晰、简洁的语法来访问序列中的单个元素或元素的范围。 索引表达式通常返回序列元素的类型。 范围表达式通常返回与源序列相同的序列类型。
若任何类型提供带 Index 或 Range 参数的索引器,则该类型可分别显式支持索引或范围。 采用单个 Range 参数的索引器可能会返回不同的序列类型,如 System.Span<T>。

重要

使用范围运算符的代码的性能取决于序列操作数的类型。
范围运算符的时间复杂度取决于序列类型。 例如,如果序列是 string 或数组,则结果是输入中指定部分的副本,因此,时间复杂度为 O(N)(其中 N 是范围的长度)。 另一方面,如果它是 System.Span<T> System.Memory<T>,则结果引用相同的后备存储,这意味着没有副本且操作为 O(1)。
除了时间复杂度外,这还会产生额外的分配和副本,从而影响性能。 在性能敏感的代码中,考虑使用 Span<T>Memory<T> 作为序列类型,因为不会为其分配范围运算符。

若类型包含名称为 Length Count 的属性,属性有可访问的 Getter 并且其返回类型为 int,则此类型为可计数类型。**** 不显式支持索引或范围的可计数类型可能为它们提供隐式支持。 有关详细信息,请参阅功能建议说明的隐式索引支持和隐式范围支持部分。 使用隐式范围支持的范围将返回与源序列相同的序列类型。
例如,以下 .NET 类型同时支持索引和范围:String、Span<T> 和 ReadOnlySpan<T>。 List<T> 支持索引,但不支持范围。
Array 具有更多的微妙行为。 单个维度数组同时支持索引和范围。 多维数组则不支持。 多维数组的索引器具有多个参数,而不是一个参数。 交错数组(也称为数组的数组)同时支持范围和索引器。 下面的示例演示如何循环访问交错数组的矩形子节。 它循环访问位于中心的节,不包括前三行和后三行,以及每个选定行中的前两列和后两列:

var jagged = new int[10][]
{
  new int[10] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
  new int[10] { 10,11,12,13,14,15,16,17,18,19},
  new int[10] { 20,21,22,23,24,25,26,27,28,29},
  new int[10] { 30,31,32,33,34,35,36,37,38,39},
  new int[10] { 40,41,42,43,44,45,46,47,48,49},
  new int[10] { 50,51,52,53,54,55,56,57,58,59},
  new int[10] { 60,61,62,63,64,65,66,67,68,69},
  new int[10] { 70,71,72,73,74,75,76,77,78,79},
  new int[10] { 80,81,82,83,84,85,86,87,88,89},
  new int[10] { 90,91,92,93,94,95,96,97,98,99},
};

var selectedRows = jagged[3..^3];

foreach (var row in selectedRows)
{
  var selectedColumns = row[2..^2];
  foreach (var cell in selectedColumns)
  {
    Console.Write($"{cell}, ");
  }
  Console.WriteLine();
}

在所有情况下,Array 的范围运算符都会分配一个数组来存储返回的元素。

索引和范围的应用场景

要分析较大序列的一部分时,通常会使用范围和索引。 在准确读取所涉及的序列部分这一方面,新语法更清晰。 本地函数 MovingAverageRange 为参数。 然后,该方法在计算最小值、最大值和平均值时仅枚举该范围。 在项目中尝试以下代码:

int[] sequence = Sequence(1000);

for(int start = 0; start < sequence.Length; start += 100)
{
  Range r = start..(start+10);
  var (min, max, average) = MovingAverage(sequence, r);
  Console.WriteLine($"From {r.Start} to {r.End}:  \tMin: {min},\tMax: {max},\tAverage: {average}");
}

for (int start = 0; start < sequence.Length; start += 100)
{
  Range r = ^(start + 10)..^start;
  var (min, max, average) = MovingAverage(sequence, r);
  Console.WriteLine($"From {r.Start} to {r.End}: \tMin: {min},\tMax: {max},\tAverage: {average}");
}

(int min, int max, double average) MovingAverage(int[] subSequence, Range range) =>
  (
    subSequence[range].Min(),
    subSequence[range].Max(),
    subSequence[range].Average()
  );

int[] Sequence(int count) =>
  Enumerable.Range(0, count).Select(x => (int)(Math.Sqrt(x) * 100)).ToArray();

以上就是详解c#索引(Index)和范围(Range)的详细内容,更多关于c# 索引和范围的资料请关注我们其它相关文章!

(0)

相关推荐

  • 谈谈c#中的索引器

    概念 索引器(Indexer) 允许类中的对象可以像数组那样方便.直观的被引用.当为类定义一个索引器时,该类的行为就会像一个 虚拟数组(virtual array) 一样. 索引器可以有参数列表,且只能作用在实例对象上,而不能在类上直接作用. 可以使用数组访问运算符([ ])来访问该类的实例. 索引器的行为的声明在某种程度上类似于属性(property).属性可使用 get 和 set 访问器来定义索引器.但是属性返回或设置的是一个特定的数据成员,而索引器返回或设置对象实例的一个特定值. 定义一

  • C# 中 System.Index 结构体和 Hat 运算符(^)的使用示例

    翻译自 John Demetriou 2019年2月17日 的文章 <C# 8 – Introducing Index Struct And A Brand New Usage For The Hat Operator> 今天我们要讲的是 Hat 运算符(^).目前为止,Hat 运算符(^)已经被用作布尔类型的异或运算符,以及字节.整型类型的按位异或运算符.在 C# 8 中,它有一个新的用法. 这个运算符的新用法是自动创建 Index 结构体的实例.那什么是 Index 结构呢?这在 C# 8

  • C#巧用DateTime预设可选的日期范围(如本年度、本季度、本月等)

    本文实例为大家分享了C# DateTime预设可选的日期范围的相关代码,可以选择本年度.本季度.本月等,供大家参考,具体内容如下 效果: 大家在做报表或查询的时候都会有给用户预设一些可选的日期范围(如上图) 如本年度销售额.本季度利润.本月新增客户 C#里内置的DateTime基本上都可以实现这些功能,巧用DateTime会使你处理这些事来变轻松多了 //今天 DateTime.Now.Date.ToShortDateString(); //昨天,就是今天的日期减一 DateTime.Now.A

  • C# 获取当前年份的周期及周期所在日期范围(推荐)

    最近有一个项目要用到年份周期,用于数据统计图表展示使用,当中用到年份周期,以及年份周期所在的日期范围.当初设想通过已知数据来换算年份周期,经过搜索资料发现通过数据库SQL语句来做,反而更加复杂.现在改变思路通过C#后台代码来算出两段日期范围中年份周期,在依据年份周期所对应的日期范围进行数据库查询进行统计.需要解决以下两个点问题, 第一点:依据日期查找所在年份的第几周: 第二点:依据年份所在的周期计算出周期所在的日期范围. using System; using System.Collection

  • C# lambda表达式应用如何找出元素在list中的索引

    1.先写个规则方法 private bool check(string str){ return str.EndsWith("xxx"); } 2.再写个Predicate Predicate<string> predicate=new Predicate<string>(check)); 如果逻辑不复杂,可以这样写 private void OpenMenu(GameObject gob){ Predicate<string> predicate=

  • C# 8.0中的范围类型(Range Type)示例详解

    前言 C# 语言是在2000发布的,至今已正式发布了7个版本,每个版本都包含了许多令人兴奋的新特性和功能更新.同时,C# 每个版本的发布都与同时期的 Visual Studio 以及 .NET 运行时版本高度耦合,这也有助于开发者更好的学习掌握 C#,并将其与 Visual Studio 以及 .NET 的使用结合起来. C# 8.0中加入了一个新的范围类型(Range Type). 这里我们首先展示一些代码,并一步一步为代码添加一些不同的东西, 为大家展示一下范围类型的功能和用法. 我们最原始

  • C#实现AddRange为数组添加多个元素的方法

    本文实例讲述了C#实现AddRange为数组添加多个元素的方法.分享给大家供大家参考.具体实现方法如下: ArrayList ab = new ArrayList(); ab.Add("a"); //old fashioned way ab.Add("b"); ArrayList abcd = new ArrayList(); abcd.AddRange(new string[] {"a","b","c",

  • 浅析C# 索引器(Indexer)

    索引器(Indexer) 允许一个对象可以像数组一样被索引.当您为类定义一个索引器时,该类的行为就会像一个 虚拟数组(virtual array) 一样.您可以使用数组访问运算符([ ])来访问该类的实例. 语法 一维索引器的语法如下: element-type this[int index] { // get 访问器 get { // 返回 index 指定的值 } // set 访问器 set { // 设置 index 指定的值 } } 索引器(Indexer)的用途 索引器的行为的声明在

  • 详解c#索引(Index)和范围(Range)

    范围和索引为访问序列中的单个元素或范围提供了简洁的语法. 在本教程中,你将了解: 对某个序列中的范围使用该语法. 了解每个序列开头和末尾的设计决策. 了解 Index 和 Range 类型的应用场景. 对索引和范围的语言支持 此语言支持依赖于两个新类型和两个新运算符: System.Index 表示一个序列索引. 来自末尾运算符 ^ 的索引,指定一个索引与序列末尾相关. System.Range 表示序列的子范围. 范围运算符 ..,用于指定范围的开始和末尾,就像操作数一样. 让我们从索引规则开

  • Pandas时间序列基础详解(转换,索引,切片)

    时间序列的类型: 时间戳:具体的时刻 固定的时间区间:例如2007年的1月或整个2010年 时间间隔:由开始时间和结束时间表示,时间区间可以被认为是间隔的特殊情况 实验时间和消耗时间:每个时间是相对于特定开始时间的时间的量度,(例如自从被放置在烤箱中每秒烘烤的饼干的直径) 日期和时间数据的类型及工具 datetime模块中的类型: date 使用公历日历存储日历日期(年,月,日) time 将时间存储为小时,分钟,秒,微秒 datetime 存储日期和时间 timedelta 表示两个datet

  • 详解Linux索引节点inode

    1.inode简介 理解inode,要从文件储存说起.文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector).每个扇区储存512字节(相当于0.5KB).操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个"块"(block).这种由多个扇区组成的"块",是文件存取的最小单位."块"的大小,最常见的是4KB,即连续八个 sector组成一个 block.文件数据都储

  • mysql之explain使用详解(分析索引)

    explain显示了mysql如何使用索引来处理select语句以及连接表.可以帮助选择更好的索引和写出更优化的查询语句. 使用方法,在select语句前加上explain就可以了,如: explain select * from statuses_status where id=11; explain列的解释 table:显示这一行的数据是关于哪张表的 type:这是重要的列,显示连接使用了何种类型.从最好到最差的连接类型为const.eq_reg.ref.range.indexhe和all

  • 详解MySQL索引原理以及优化

    前言 本文是美团一位大佬写的,还不错拿出来和大家分享下,代码中嵌套在html中sql语句是java框架的写法,理解其sql要执行的语句即可. 背景 MySQL凭借着出色的性能.低廉的成本.丰富的资源,已经成为绝大多数互联网公司的首选关系型数据库.虽然性能出色,但所谓"好马配好鞍",如何能够更好的使用它,已经成为开发工程师的必修课,我们经常会从职位描述上看到诸如"精通MySQL"."SQL语句优化"."了解数据库原理"等要求.我

  • 图文详解Mysql索引的最左前缀原则

    目录 前言 1. 定义 2. 全索引顺序 3. 部分索引顺序 3.1 正序 3.2 乱序 4. 模糊索引 5. 范围索引 总结 前言 之所以有这个最左前缀索引 归根结底是mysql的数据库结构 B+树 在实际问题中 比如 索引index (a,b,c)有三个字段, 使用查询语句select * from table where c = '1' ,sql语句不会走index索引的 select * from table where b =‘1’ and c ='2' 这个语句也不会走index索引

  • 详解mysql索引总结----mysql索引类型以及创建

    关于MySQL索引的好处,如果正确合理设计并且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的MySQL就是一个人力三轮车.对于没有索引的表,单表查询可能几十万数据就是瓶颈,而通常大型网站单日就可能会产生几十万甚至几百万的数据,没有索引查询会变的非常缓慢.还是以WordPress来说,其多个数据表都会对经常被查询的字段添加索引,比如wp_comments表中针对5个字段设计了BTREE索引. 一个简单的对比测试 以我去年测试的数据作为一个简单示例,20多条数据源随机生成200万条

  • 详解python中index()、find()方法

    python中index().find()方法,具体内容如下: index() 方法检测字符串中是否包含子字符串 str ,如果指定 beg(开始) 和 end(结束) 范围,则检查是否包含在指定范围内,该方法与 python find()方法一样,只不过如果str不在 string中会报一个异常.影响后面程序执行 index()方法语法:str.index(str, beg=0, end=len(string)) str -- 指定检索的字符串 beg -- 开始索引,默认为0. end --

  • MongoDB TTL索引的实例详解

    MongoDB TTL索引的实例详解 TTL索引是一种特殊类型的单字段索引,主要用于当满足某个特定时间之后自动删除相应的文档.也就是说集合中的文档有一定的有效期,超过有效期的文档就会失效,会被移除.也即是数据会过期.过期的数据无需保留,这种情形适用于如机器生成的事件数据,日志和会话信息等等.本文主要描述TTL索引的使用. 一.TTL索引 创建方法 db.collection.createIndex(keys, options) options: expireAfterSeconds 指定多少秒或

  • MySQL索引最左匹配原则实例详解

    目录 简介 准备 理论详解 聚集索引和非聚集索引 回表查询 索引覆盖 最左匹配原则 详细规则 补充:为什么要使用联合索引 总结 简介 这篇文章的初衷是很多文章都告诉你最左匹配原则,却没有告诉你,实际场景下它到底是如何工作的,本文就是为了阐述清这个问题. 准备 为了方面后续的说明,我们首先建立一个如下的表(MySQL5.7),表中共有5个字段(a.b.c.d.e),其中a为主键,有一个由b,c,d组成的联合索引,存储引擎为InnoDB,插入三条测试数据.强烈建议自己在MySQL中尝试本文的所有语句

随机推荐