服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C# 如何使用 Index 和 Range 简化集合操作

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

2022-11-02 11:10WeihanLi C#

这篇文章主要介绍了C# 如何使用 Index 和 Range 简化集合操作,帮助大家更好的理解和学习使用c#,感兴趣的朋友可以了解下

Intro

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

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

Sample

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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();

输出结果如下:

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

Index

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

Index:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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 类型的索引器就可以了

写一个简单的小示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 来指定开始和结束

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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 ..) 都只是语法糖,本质上是调用 Index、Range

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

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

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

以上就是C# 如何使用 Index 和 Range 简化集合操作的详细内容,更多关于c# 使用 Index 和 Range 简化集合操作的资料请关注服务器之家其它相关文章!

原文链接:https://www.cnblogs.com/weihanli/p/14444780.html

延伸 · 阅读

精彩推荐
  • C#深入理解StringBuilder的使用方法

    深入理解StringBuilder的使用方法

    下面小编就为大家带来一篇深入理解StringBuilder的使用方法。小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    编程之家5602021-11-22
  • C#C# 实现dataGridView选中一行右键出现菜单的示例代码

    C# 实现dataGridView选中一行右键出现菜单的示例代码

    这篇文章主要介绍了C# 实现dataGridView选中一行右键出现菜单,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要...

    孙正嗯大正5432022-10-09
  • C#C# 8.0新特性介绍

    C# 8.0新特性介绍

    C# 语言是在2000发布的,至今已正式发布了7个版本,每个版本都包含了许多令人兴奋的新特性和功能更新。下面通过本文给大家分享下C# 8.0的三个令人兴奋...

    葡萄城控件技术团队11002022-01-25
  • C#Unity工具类ScrollView实现拖拽滑动翻页

    Unity工具类ScrollView实现拖拽滑动翻页

    这篇文章主要为大家详细介绍了Unity工具类ScrollView实现拖拽滑动翻页,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一...

    真像大白阿7072022-09-02
  • C#浅谈C#跨线程调用窗体控件(比如TextBox)引发的线程安全问题

    浅谈C#跨线程调用窗体控件(比如TextBox)引发的线程安全问题

    下面小编就为大家分享一篇浅谈C#跨线程调用窗体控件(比如TextBox)引发的线程安全问题,具有很好的参考价值,希望对大家有所帮助...

    绛河7662022-02-10
  • C#C#中增加SQLite事务操作支持与使用方法

    C#中增加SQLite事务操作支持与使用方法

    这篇文章主要介绍了C#中增加SQLite事务操作支持与使用方法,结合实例形式分析了C#中针对SQLite事务操作的添加及使用技巧,需要的朋友可以参考下...

    changtianshuiyue7812022-01-17
  • C#C# 操作网络适配器的示例

    C# 操作网络适配器的示例

    这篇文章主要介绍了C# 操作网络适配器的示例,帮助大家更好的理解和学习c#,感兴趣的朋友可以了解下...

    一只独行的猿5092022-10-13
  • C#C#操作 JSON方法汇总

    C#操作 JSON方法汇总

    本文给大家汇总了一下使用C#操作Json的方法,非常的简单实用,有需要的小伙伴可以参考下...

    C#教程网4262021-10-29