---
tags: C# , Language
---
# Index & Range
## 前言
- Index & Range 是 C# 8.0 才提供的功能 , 其概念其實在別的語言早就有了. (e.g. Python) .
- Index 和 Range 提供簡潔的語法 , 用於存取序列中的指定位置的單一元素或範圍
- Index 可以從後面開始數起.
- Range **目前**只能用在下列 (沒有 List)
- 陣列
- 字串
- Span
- ReadOnlySpan
## Index
```C#
public struct Index : IEquatable<Index>
{
public Index(int value, bool fromEnd = false);
public static Index Start => new Index(0);
public static Index End => new Index(~0);
public static Index FromStart(int value);
public static Index FromEnd(int value);
public int Value { get; }
public bool IsFromEnd { get; }
public int GetOffset(int length);
public override bool Equals(object? value);
public bool Equals(Index other);
public override int GetHashCode();
public static implicit operator Index(int value);
public override string ToString();
}
```
- Index 是 readonly struct
- Index 由 0 開始計算
- 由 Index 的建構子可發現 , 索引存在正負的概念.
- 第一個參數 value , 代表位置
- 第二個參數 fronEnd , 代表此位置是否為由後往前推算
### 概念
```C#
var 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
```
### 建立方式
- 建構式
```C#
var index1 = new Index(3, false); // 表第'3'個位置
var index2 = new Index(3, true); // 表倒數第三個位置
```
- 靜態方法
```C#
var index1 = Index.FromStart(3); // 表第'3'個位置
var index2 = Index.FromEnd(3); // 表倒數第三個位置
```
- 靜態屬性
```C#
var index1 = Index.Start; // 0 , 表第零個位置
var index2 = Index.End; // ^0 == set's length , 表第 set's length 個位置
```
- 隱性轉換
```C#
var index1 = 3; // 表第'3'個位置
var index2 = ^3; // 表倒數第三個位置
```
### Index 範例
```C#
var list = new List<int> { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
// 建構式
var index1 = new Index(3, false);
var index2 = new Index(3, true);
// 隱性轉換
var index3 = 3;
var index4 = ^3;
// 靜態方法
var index5 = Index.FromEnd(1);
var index6 = Index.FromStart(1);
// 靜態屬性
var index7 = Index.Start;
var index8 = Index.End; // ^0
Console.WriteLine(list[index1]);
Console.WriteLine(list[index2]);
Console.WriteLine(list[index3]);
Console.WriteLine(list[index4]);
Console.WriteLine(list[index5]);
Console.WriteLine(list[index6]);
Console.WriteLine(list[index7]);
//Console.WriteLine(list[index8]); // Throw OutOfRangeException
// 輸出結果
6
3
6
3
1
8
9
```
### GetOffset
- Calculate the offset from the start using the giving collection length.
```C#
var index = Index.FromStart(2);
Console.WriteLine($"Offset : {index.GetOffset(10)}");
Console.WriteLine($"Offset : {index.GetOffset(1)}");
var index2 = ^2;
Console.WriteLine($"Offset : {index2.GetOffset(10)}");
Console.WriteLine($"Offset : {index2.GetOffset(1)}");
// 輸出結果
Offset : 2
Offset : 2
Offset : 8
Offset : -1
```
## Range
```C#
public readonly struct Range : IEquatable<Range>
{
public Index Start { get; }
public Index End { get; }
public Range(Index start, Index end);
public override bool Equals(object? value);
public bool Equals(Range other);
public override int GetHashCode();
public override string ToString();
public static Range StartAt(Index start) ;
public static Range EndAt(Index end);
public static Range All => new Range(Index.Start, Index.End);
public (int Offset, int Length) GetOffsetAndLength(int length);
}
```
- Range 是 readonly struct
- [ startIndex ... endIndex ] , endIndex 不包含 End Index (上包 下不包)
- startIndex 必須小於 endIndex . **目前**尚不支援倒著數
### 建立方式
- 建構式
```C#
var range = new Range(1, ^2);
```
- 靜態方法
```C#
var startAt = Range.StartAt(1); // 從位置 1 開始直到最後
var endAt = Range.EndAt(1); // 在位置 1 以前 (不包含位置 1 )
```
- .. 運算子
```C#
var range = 1..3;
```
### Range 簡單範例
```C#
var 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
};
var start = 2 ;
foreach (var s in words[start..4])
{
Console.WriteLine(s);
}
// 輸出結果
brown
fox
```
### Range 範例
```C#
var 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
};
Console.WriteLine();
var range = new Range(0, ^8);
var ranges = new List<Range>
{
range,
Range.StartAt(7),
Range.StartAt(^2),
Range.EndAt(2),
Range.EndAt(^7),
{..^7},
{7..},
{4..^3},
{1..3},
{..},
};
foreach (var range1 in ranges)
{
foreach (var str in words[range1])
{
Console.WriteLine(str);
}
Console.WriteLine("===========================");
}
```
##### 輸出結果
```
The
===========================
lazy
dog
===========================
lazy
dog
===========================
The
quick
===========================
The
quick
===========================
The
quick
===========================
lazy
dog
===========================
jumped
over
===========================
quick
brown
===========================
The
quick
brown
fox
jumped
over
the
lazy
dog
===========================
```
### Range OutOfRangeException
```C#
var 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
};
var range = words[8..10]; // 會拋出例外
```
## 參考
[C# 8.0 搶先看 -- Ranges and Indicies (2) Range](https://dotblogs.com.tw/billchung/2018/12/26/232311)
[C# 8.0 搶先看 -- Ranges and Indicies (1) Index](https://dotblogs.com.tw/billchung/2018/12/24/220436)
[[C#] 8.0 新功能 - 索引與範圍](https://blog.kevinyang.net/2020/01/16/csharp-8-index-range/)
[索引和範圍](https://docs.microsoft.com/zh-tw/dotnet/csharp/whats-new/csharp-8#indices-and-ranges)
### Thank you!
You can find me on
- [GitHub](https://github.com/s0920832252)
- [Facebook](https://www.facebook.com/fourtune.chen)
若有謬誤 , 煩請告知 , 新手發帖請多包涵
# :100: :muscle: :tada: :sheep: