---
# System prepended metadata

title: Index & Range
tags: [' Language', 'C# ']

---

---
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: 
