[C#] 配列の性質と基本操作

##概要
- 本稿では，配列の性質と初期化方法，主要な操作の実装方法について解説する．[^1]

##配列とは
- 複数の同型データを纏めて扱うための参照型データ．
- 配列には，1次元配列，多次元配列，ジャグ配列がある．
- 配列の要素には，任意の型を指定できる．
- **次元数と各次元の長さは，配列インスタンスの作成時に設定**され，インスタンスの有効期間中にこれらの値を変更することはできない．
- `n`個の要素を含む配列には`0`から`n-1`までのインデックスが与えられる．
- 数値配列要素の既定値は`0`に設定され，参照要素は`null`に設定される．
- ジャグ配列は「配列の配列」であり，各要素の既定値は`null`に設定される．

##`System.Array`
- 全ての配列は抽象クラス`System.Array`を継承する．
- `System.Array`は`IEnumerable`を実装するので，すべての配列に対して`foreach`ステートメントや`System.Linq`拡張メソッドを利用できる．

|クラス|説明|
|:---:|:---|
|[Array](https://docs.microsoft.com/ja-jp/dotnet/api/system.array?view=netcore-3.1)|配列の作成，操作，検索，および並べ替えを行うメソッドを提供します．|

- `System.Array`が継承するインターフェースは下記の通り．

|インターフェース|説明|
|:---:|:---|
|[IEnumerable](https://docs.microsoft.com/ja-jp/dotnet/api/system.collections.ienumerable?view=netcore-3.1)|非ジェネリック コレクションに対する単純な反復処理をサポートする列挙子を公開します． |
|[IList](https://docs.microsoft.com/ja-jp/dotnet/api/system.collections.ilist?view=netcore-3.1)|インデックスによって個別にアクセスできるオブジェクトの非ジェネリック コレクションを表します．|
|[ICollection](https://docs.microsoft.com/ja-jp/dotnet/api/system.collections.icollection?view=netcore-3.1)|すべての非ジェネリック コレクションについて，サイズ，列挙子，および同期メソッドを定義します．|
|[ICloneable](https://docs.microsoft.com/ja-jp/dotnet/api/system.icloneable?view=netcore-3.1)|値は，既存のインスタンスと同じクラスの新しいインスタンスを作成する複製をサポートします．|
|[IStructuralComparable](https://docs.microsoft.com/ja-jp/dotnet/api/system.collections.istructuralcomparable?view=netcore-3.1)|コレクション オブジェクトの構造比較をサポートします．|
|[IStructuralEquatable](https://docs.microsoft.com/ja-jp/dotnet/api/system.collections.istructuralequatable?view=netcore-3.1)|オブジェクトの構造が等価かどうかの比較をサポートするメソッドを定義します．|

##配列の初期化

###一次元配列

```C#
// 型と長さを指定して宣言
var arr1 = new string[3];
arr1[0] = "a";
arr1[1] = "b";
arr1[2] = "c";

// ブレースで初期値を設定
var arr2 = new string[] { "a", "b", "c" };

// 宣言側の型省略
string[] arr3 = { "a", "b", "c" };

// 暗黙的型付け配列
var arr4 = new[] { "a", "b", "c" };

```

###多次元配列

```C#
// 型と長さを指定して宣言
var arr1 = new string[2, 2];
arr1[0, 0] = "a";
arr1[0, 1] = "b";
arr1[1, 0] = "c";
arr1[1, 1] = "d";

// ブレースで初期値を設定
var arr2 = new string[,] { { "a", "b" }, { "c", "d" } };

// 宣言側の型省略
string[,] arr3 = { { "a", "b" }, { "c", "d" } };

// 暗黙的型付け配列
var arr4 = new[,] { { "a", "b" }, { "c", "d" } };
```

###ジャグ配列

```C#
// 型と長さを指定して宣言
var arr1 = new string[2][];
arr1[0] = new string[2];
arr1[1] = new string[3];
arr1[0][0] = "a";
arr1[0][1] = "b";
arr1[1][0] = "c";
arr1[1][1] = "d";
arr1[1][2] = "e";

// ブレースで初期値を設定
var arr2 = new string[][] { new string[] { "a", "b" }, new string[] { "c", "d", "e" } };

// 宣言側の型省略
string[][] arr3 = { new string[] { "a", "b" }, new string[] { "c", "d", "e" } };

// 暗黙的型付け配列
var arr4 = new[] { new[] { "a", "b" }, new[] { "c", "d", "e" } };
```

##配列の操作

###値の取得

|メソッド|説明|
|:---:|:---|
|[GetValue(int *index*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.getvalue?view=netcore-3.1#System_Array_GetValue_System_Int32_)|1 次元配列内の指定した位置にある値を`Object`型で取得します．<br>*index* : 取得する配列の位置．|
|[GetValue(params int[] *indices*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.getvalue?view=netcore-3.1#System_Array_GetValue_System_Int32___)|多次元配列内の指定した位置にある値を`Object`型で取得します．<br>*indices* : 取得する配列の位置を指定するインデックスを表すint型の1次元配列．|

```C#
// 1次元配列
var arr1 = new[] { "C", "D", "E", "F", "G", "A", "B"};
var s1 = arr1[0];                   // "C"：先頭から0番目の値を取得
var s2 = (string)arr1.GetValue(1);  // "D"：先頭から1番目の値を取得
var s3 = arr1[^1];                  // "B"：末尾から1個目の値を取得(C# 8.0-)
var s4 = arr1[^2];                  // "A"：末尾から2個目の値を取得(C# 8.0-)

// 多次元配列
var arr2 = new[,] { { "香", "桂", "銀", "金", "玉", "金", "銀", "桂" , "香" },
                    { "　", "飛", "　", "　", "　", "　", "　", "角" , "　" },
                    { "歩", "歩", "歩", "歩", "歩", "歩", "歩", "歩" , "歩" },
                    { "　", "　", "　", "　", "　", "　", "　", "　" , "　" },
                    { "　", "　", "　", "　", "　", "　", "　", "　" , "　" },
                    { "　", "　", "　", "　", "　", "　", "　", "　" , "　" },
                    { "歩", "歩", "歩", "歩", "歩", "歩", "歩", "歩" , "歩" },
                    { "　", "角", "　", "　", "　", "　", "　", "飛" , "　" },
                    { "香", "桂", "銀", "金", "王", "金", "銀", "桂" , "香" } };
var rook1 = arr2[1, 1];                   // "飛"
var rook2 = (string)arr2.GetValue(1, 1);  // "飛"

// ジャグ配列
var arr3 = new[] { new[] { "香", "桂", "銀", "金", "玉", "金", "銀", "桂" , "香" },
                   new[] { "　", "飛", "　", "　", "　", "　", "　", "角" , "　" },
                   new[] { "歩", "歩", "歩", "歩", "歩", "歩", "歩", "歩" , "歩" },
                   new[] { "　", "　", "　", "　", "　", "　", "　", "　" , "　" },
                   new[] { "　", "　", "　", "　", "　", "　", "　", "　" , "　" },
                   new[] { "　", "　", "　", "　", "　", "　", "　", "　" , "　" },
                   new[] { "歩", "歩", "歩", "歩", "歩", "歩", "歩", "歩" , "歩" },
                   new[] { "　", "角", "　", "　", "　", "　", "　", "飛" , "　" },
                   new[] { "香", "桂", "銀", "金", "王", "金", "銀", "桂" , "香" } };
var bishop1 = arr3[1][7];                                          // "角"
var bishop2 = (string)((string[])arr3.GetValue(1)).GetValue(7);    // "角"
``` 

###値の設定

|メソッド|説明|
|:---:|:---|
|[SetValue(Object *value*, int *index*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.setvalue?view=netcore-3.1#System_Array_SetValue_System_Object_System_Int32_)|1次元配列内の指定した位置にある要素に値を設定します．<br>*value* : 指定した要素の新しい値．<br>*index* : 指定する配列の位置．|
|[SetValue (object *value*, params int[] *indices*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.setvalue?view=netcore-3.1#System_Array_SetValue_System_Object_System_Int32___)|多多次元配列内の指定した位置にある要素に値を設定します．<br>*value* : 指定した要素の新しい値．<br>*indices* : 指定する配列の位置を指定するインデックスを表すint型の1次元配列．|
|[Fill\<*T*>(T[] *array*, T *value*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.fill?view=netcore-3.1#System_Array_Fill__1___0_____0_)|指定された値を，指定された配列の各要素に割り当てます．|
|[Fill\<*T*>(T[] *array*, T *value*, int *startIndex*, int *count*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.fill?view=netcore-3.1#System_Array_Fill__1___0_____0_System_Int32_System_Int32_)|指定された値を，指定された配列の各要素に割り当てます．これらの要素は，*startIndex* (包含) および次の *count* 個のインデックスの範囲内にあります．<br>*array* : 入力する配列．<br>*value* : 指定された範囲内にある要素に対する新しい値．<br>*startIndex* : 入力を開始する配列のインデックス．<br>*count* : コピーする要素の数．|

```C#
// 1次元配列
var arr1 = new[] { "C", "D", "E", "F", "G", "A", "B" };
arr1[0] = "A";                  // { "A", "D", "E", "F", "G", "A", "B" }
arr1.SetValue("B", 0);          // { "B", "D", "E", "F", "G", "A", "B" }
Array.Fill(arr1, "A");          // { "A", "A", "A", "A", "A", "A", "A" }
Array.Fill(arr1, "B", 1, 5);    // { "A", "B", "B", "B", "B", "B", "A" }

// 多次元配列
var arr2 = new[,] { { "香", "桂", "銀", "金", "玉", "金", "銀", "桂" , "香" },
                    { "　", "飛", "　", "　", "　", "　", "　", "角" , "　" },
                    { "歩", "歩", "歩", "歩", "歩", "歩", "歩", "歩" , "歩" },
                    { "　", "　", "　", "　", "　", "　", "　", "　" , "　" },
                    { "　", "　", "　", "　", "　", "　", "　", "　" , "　" },
                    { "　", "　", "　", "　", "　", "　", "　", "　" , "　" },
                    { "歩", "歩", "歩", "歩", "歩", "歩", "歩", "歩" , "歩" },
                    { "　", "角", "　", "　", "　", "　", "　", "飛" , "　" },
                    { "香", "桂", "銀", "金", "王", "金", "銀", "桂" , "香" } };
arr2[5, 2] = "歩";
arr2.SetValue("歩", 5, 2);

// ジャグ配列
var arr3 = new[] { new[] { "香", "桂", "銀", "金", "玉", "金", "銀", "桂" , "香" },
                   new[] { "　", "飛", "　", "　", "　", "　", "　", "角" , "　" },
                   new[] { "歩", "歩", "歩", "歩", "歩", "歩", "歩", "歩" , "歩" },
                   new[] { "　", "　", "　", "　", "　", "　", "　", "　" , "　" },
                   new[] { "　", "　", "　", "　", "　", "　", "　", "　" , "　" },
                   new[] { "　", "　", "　", "　", "　", "　", "　", "　" , "　" },
                   new[] { "歩", "歩", "歩", "歩", "歩", "歩", "歩", "歩" , "歩" },
                   new[] { "　", "角", "　", "　", "　", "　", "　", "飛" , "　" },
                   new[] { "香", "桂", "銀", "金", "王", "金", "銀", "桂" , "香" } };
arr3[5][2] = "歩";
((string[])arr3.GetValue(5)).SetValue("歩", 2);
``` 

###長さの取得

|プロパティ|説明|
|:---:|:---|
|[Length](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.length?view=netcore-3.1)|配列のすべての次元内の要素の総数を取得します．|

|メソッド|説明|
|:---:|:---|
|[GetLength(int *dimension*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.getlength?view=netcore-3.1#System_Array_GetLength_System_Int32_)|配列の指定した次元にある要素の数を取得します．<br>*dimension* : 長さを指定する必要がある配列の`0`から始まる次元．|

```C#
var arr1 = new int[3];
var l0 = arr1.Length;           // 3
var l1 = arr1.GetLength(0);     // 3

var arr2 = new int[3, 5];
var l2 = arr2.Length;           // 15
var l3 = arr2.GetLength(0);     // 3
var l4 = arr2.GetLength(1);     // 5

var arr3 = new[] { new[] { 0, 1, 2 }, new[] { 0, 1, 2, 3 } };
var l5 = arr3.Length;           // 2
var l6 = arr3[0].Length;        // 3
var l7 = arr3[0].GetLength(0);  // 3
var l8 = arr3[1].Length;        // 4
var l9 = arr3[1].GetLength(0);  // 4
```

###次元の取得

|プロパティ|説明|
|:---:|:---|
|[Rank](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.rank?view=netcore-3.1)|配列の次元数を取得します．|

```C#
var arr1 = new int[3];
var d1 = arr1.Rank;     // 1

var arr2 = new int[3, 5];
var d2 = arr2.Rank;     // 2

var arr3 = new[] { new[] { 0, 1, 2 }, new[] { 0, 1, 2, 3 } };
var d3 = arr3.Rank;     // 1
```

###配列の生成

|メソッド|説明|
|:---:|:---|
|[Empty\<*T*>](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.empty?view=netcore-3.1)|空の配列を返します．<br>*T* : 作成する配列の型|
|[CreateInstance(Type *elementType*, int *length*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.createinstance?view=netcore-3.1#System_Array_CreateInstance_System_Type_System_Int32_)|型と長さを指定して，1次元の配列を`Array`型で作成します．<br>*elementType* : 作成する配列の型．<br>*length* : 作成する配列の長さ．|
|[CreateInstance(Type *elementType*, params int[] *lengths*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.createinstance?view=netcore-3.1#System_Array_CreateInstance_System_Type_System_Int32___)|型と次元の長さを指定して，多次元配列を`Array`型で作成します．<br>*elementType* : 作成する配列の型．<br>*lengths* : 作成する配列の各次元の長さを表す配列．|

```C#
// 空の配列を作成
var arr1 = Array.Empty<int>();                                  // new int[0]
var arr2 = Array.Empty<string>();                               // new string[0]

// 型と長さを指定して配列を作成
var arr3 = (int[])Array.CreateInstance(typeof(int), 2);         // new int[2]
var arr4 = (string[])Array.CreateInstance(typeof(string), 3);   // new string[3]
var arr5 = (int[,])Array.CreateInstance(typeof(int), 3, 2);     // new int[3, 2]
```

###初期化

|メソッド|説明|
|:---:|:---|
|[Initialize](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.initialize?view=netcore-3.1)|値型のパラメーターなしのコンストラクターを呼び出すことで，この値型配列の各要素を初期化します．<br>このメソッドは，コンストラクターを持つ値型に対してのみ使用できます．|
|[Clear(Array *array*, int *index*, int *length*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.clear?view=netcore-3.1)|配列内にある要素の範囲を，各要素の型の既定値に設定します．<br>*array* : 要素を削除する必要がある配列．<br>*index* : 削除する要素の範囲の開始インデックス．<br>*length* : 削除する要素の数．|

###シャローコピー[^2]

|メソッド|説明|
|:---:|:---|
|[Clone](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.clone?view=netcore-3.1)|配列の簡易コピーを`Object`型で作成します．|
|[Copy(Array *sourceArray*, Array *destinationArray*, int *length*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.copy?view=netcore-3.1#System_Array_Copy_System_Array_System_Array_System_Int32_)|一方の配列の要素範囲を他方の配列にコピーします．<br>*sourceArray* : コピーするデータを格納している配列．<br>*destinationArray* : データを受け取る配列．<br>*length* : コピーする要素の数．|
|[Copy(Array *sourceArray*, int *sourceIndex*, Array *destinationArray*, int *destinationIndex*, int *length*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.copy?view=netcore-3.1#System_Array_Copy_System_Array_System_Int32_System_Array_System_Int32_System_Int32_)|指定したコピー元インデックスを開始位置として Array から要素の範囲をコピーし，指定したコピー先インデックスを開始位置として他の Array にそれらの要素を貼り付けます．<br>*sourceArray* : コピーするデータを格納している配列．<br>*sourceIndex* : コピー操作の開始位置となる *sourceArray* 内のインデックス．<br>*destinationArray* : データを受け取る配列．<br>*length* : コピーする要素の数．|
|[ConstrainedCopy(Array *sourceArray*, int *sourceIndex*, Array *destinationArray*, int *destinationIndex*, int *length*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.constrainedcopy?view=netcore-3.1)|指定したコピー元インデックスを開始位置として Array から要素の範囲をコピーし，指定したコピー先インデックスを開始位置として他の Array にそれらの要素を貼り付けます． **コピーが完全に成功しない限り，変更は一切適用されません．**<br>*sourceArray* : コピーするデータを格納している配列．<br>*sourceIndex* : コピー操作の開始位置となる *sourceArray* 内のインデックス．<br>*destinationArray* : データを受け取る配列．<br>*length* : コピーする要素の数．|

```C#
var arr = new[] { 1, 2, 3, 4, 5 };
var arr1 = (int[])arr.Clone();                  // {1, 2, 3, 4, 5}

var arr2 = new int[5];
Array.Copy(arr, arr2, arr2.Length);             // {1, 2, 3, 4, 5}

var arr3 = new int[3];
Array.Copy(arr, arr3, arr3.Length);             // {1, 2, 3}

var arr4 = new int[3];
Array.Copy(arr, 0, arr4, 1,  2);                // {0, 1, 2}

var arr5 = new int[4];
Array.ConstrainedCopy(arr, 1, arr5, 1, 3);      // {0, 2, 3, 4}

// C# 8.0-
var arr6 = arr1[0..3];                          // { 1, 2, 3 }
var arr7 = arr1[1..^1];                         // { 2, 3, 4 }

var str1 = "0123456789";
var str2 = str1[1..^1];                         // "12345678"

// Copy と ConstrainedCopy の動作比較
Object[] objArray = { "The", "smallest", "prime", "number", "is", 2 };

var strArray1 = new string[6];
Array.Fill(strArray1, "?");
try
{
    Array.Copy(objArray, strArray1, strArray1.Length);
}
catch (Exception e)
{
    Console.WriteLine(e.GetType().Name);                // "InvalidCastException"
    Console.WriteLine(string.Join(" ", strArray1));     // "The smallest prime number is ?"
}


var strArray2 = new string[6];
Array.Fill(strArray2, "?");
try
{
    Array.ConstrainedCopy(objArray, 0, strArray2, 0, strArray2.Length);
}
catch (Exception e)
{
    Console.WriteLine(e.GetType().Name);                // "ArrayTypeMismatchException"
    Console.WriteLine(string.Join(" ", strArray2));     // "? ? ? ? ? ?"
}
```

###探索
|メソッド|説明|
|:---:|:---|
|[IndexOf\<*T*>(T[] *array*, T *value*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.indexof?view=netcore-3.1#System_Array_IndexOf__1___0_____0_)|指定したオブジェクトを検索し，1次元配列でそのオブジェクトが最初に見つかった位置の**インデックス**を返します．<br>*T* : 配列要素の型．<br>*array* : 検索する1次元の配列．<br>*value* : 検索するオブジェクト．|
|[IndexOf\<*T*>(T[] *array*, T *value*, int *startIndex*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.indexof?view=netcore-3.1#System_Array_IndexOf__1___0_____0_System_Int32_)|指定されたオブジェクトを1次元配列の要素範囲内で検索し，最初に見つかったオブジェクトの**インデックス**を返します． 要素範囲は，指定されたインデックスから，配列の最後までの範囲です．<br>*T* : 配列要素の型．<br>*array* : 検索する1次元の配列．<br>*value* : 検索するオブジェクト．<br>*startIndex* : 検索の開始位置を示すインデックス．|
|[IndexOf\<*T*>(T[] *array*, T *value*, int *startIndex*, int *count*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.indexof?view=netcore-3.1#System_Array_IndexOf__1___0_____0_System_Int32_System_Int32_)|指定されたオブジェクトを1次元配列の要素範囲内で検索し，最初に見つかったオブジェクトの**インデックス**を返します． 範囲は，指定されたインデックスから始まり，指定された数の要素を含む範囲です．<br>*T* : 配列要素の型．<br>*array* : 検索する1次元の配列．<br>*value* : 検索するオブジェクト．<br>*startIndex* : 検索の開始位置を示すインデックス．<br>*count* : 検索対象の範囲内にある要素の数．|
|[LastIndexOf\<*T*>(T[] *array*, T *value*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.lastindexof?view=netcore-3.1#System_Array_LastIndexOf__1___0_____0_)|指定したオブジェクトを配列全体を対象に検索し，インデックス番号の最も大きい要素の**インデックス**を返します．<br>*T* : 配列要素の型．<br>*array* : 検索する1次元の配列．<br>*value* : 検索するオブジェクト．|
|[LastIndexOf\<*T*>(T[] *array*, T *value*, int *startIndex*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.lastindexof?view=netcore-3.1#System_Array_LastIndexOf__1___0_____0_System_Int32_)|指定したオブジェクトを，配列の先頭の要素から，指定されたインデックス位置までを範囲として検索し，インデックス番号の最も大きい要素の**インデックス**を返します．<br>*T* : 配列要素の型．<br>*array* : 検索する1次元の配列．<br>*value* : 検索するオブジェクト．<br>*startIndex* : 後方検索のの開始位置を示すインデックス．|
|[LastIndexOf\<*T*>(T[] *array*, T *value*, int *startIndex*, int *count*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.lastindexof?view=netcore-3.1#System_Array_LastIndexOf__1___0_____0_System_Int32_System_Int32_)|指定したオブジェクトを，配列の指定したインデックス位置から，指定した要素数を範囲として検索し，インデックス番号の最も大きい要素の**インデックス**を返します．<br>*T* : 配列要素の型．<br>*array* : 検索する1次元の配列．<br>*value* : 検索するオブジェクト．<br>*startIndex* : 後方検索のの開始位置を示すインデックス．<br>*count* : 検索対象の範囲内にある要素の数．|
|[FindIndex\<*T*>(T[] *array*, Predicate<T> *match*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.findindex?view=netcore-3.1#System_Array_FindIndex__1___0___System_Predicate___0__)|配列全体から，指定した述語によって定義される条件に一致する要素を検索し，最もインデックス番号の小さい要素の**インデックス**を返します．<br>*T* : 配列要素の型．<br>*array* : 検索する1次元の配列．<br>*match* : 検索する要素の条件を定義する述語．|
|[FindIndex\<*T*>(T[] *array*, int *startIndex*, Predicate<T> *match*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.findindex?view=netcore-3.1#System_Array_FindIndex__1___0___System_Int32_System_Predicate___0__)|配列の指定したインデックスから最後の要素までの範囲内で，指定した述語にで定義される条件に一致する要素を検索し，最初に見つかった**インデックス**を返します．<br>*T* : 配列要素の型．<br>*array* : 検索する1次元の配列．<br>*startIndex* : 検索のの開始位置を示すインデックス．<br>*match* : 検索する要素の条件を定義する述語．|
|[FindIndex\<*T*>(T[] *array*, int *startIndex*, int *count*, Predicate<T> *match*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.findindex?view=netcore-3.1#System_Array_FindIndex__1___0___System_Int32_System_Int32_System_Predicate___0__)|配列のうち，指定したインデックスから始まり，指定した要素数が含まれる範囲の中で，指定した述語によって定義される条件に一致する要素を検索し，そのうち最もインデックス番号の小さい要素の**インデックス**を返します．<br>*T* : 配列要素の型．<br>*array* : 検索する1次元の配列．<br>*startIndex* : 検索のの開始位置を示すインデックス．<br>*count* : 検索対象の範囲内にある要素の数．<br>*match* : 検索する要素の条件．|
|[FindLastIndex\<*T*>(T[] *array*, Predicate<T> *match*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.findlastindex?view=netcore-3.1#System_Array_FindLastIndex__1___0___System_Predicate___0__)|配列全体から，指定した述語によって定義される条件に一致する要素を検索し，最もインデックス番号の大きい要素の**インデックス**を返します．<br>*T* : 配列要素の型．<br>*array* : 検索する1次元の配列．<br>*match* : 検索する要素の条件を定義する述語．|
|[FindLastIndex\<*T*>(T[] *array*, int *startIndex*, Predicate<T> *match*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.findlastindex?view=netcore-3.1#System_Array_FindLastIndex__1___0___System_Int32_System_Predicate___0__)|配列のうち，先頭の要素から指定したインデックスまでの範囲の中で，指定した述語によって定義される条件に一致する要素を検索し，そのうち最もインデックス番号の大きい要素の**インデックス**を返します．<br>*T* : 配列要素の型．<br>*array* : 検索する1次元の配列．<br>*startIndex* : 後方検索のの開始位置を示すインデックス．<br>*match* : 検索する要素の条件を定義する述語．|
|[FindLastIndex\<*T*>(T[] *array*, int *startIndex*, int *count*, Predicate<T> *match*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.findlastindex?view=netcore-3.1#System_Array_FindLastIndex__1___0___System_Int32_System_Int32_System_Predicate___0__)|配列の指定したインデックスで終わる指定した要素数の範囲内で，指定した述語によって定義される条件に一致する要素を検索し，最もインデックス番号の大きい要素の**インデックス**を返します．<br>*T* : 配列要素の型．<br>*array* : 検索する1次元の配列．<br>*startIndex* : 後方検索のの開始位置を示すインデックス．<br>*count* : 検索対象の範囲内にある要素の数．<br>*match* : 検索する要素の条件を定義する述語．|
|[Find\<*T*>(T[] *array*, Predicate<T> *match*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.find?view=netcore-3.1)|指定された述語によって定義された条件と一致する要素を検索し，配列全体の中で最もインデックス番号の小さい**要素**を返します．<br>*T* : 配列要素の型．<br>*array* : 検索する配列．<br>*match* : 検索する要素の条件を定義する述語．|
|[FindLast\<*T*>(T[] *array*, Predicate<T> *match*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.findlast?view=netcore-3.1)|指定された述語によって定義された条件と一致する要素を，配列全体を対象に検索し，最もインデックス番号の大きい**要素**を返します．<br>*T* : 配列要素の型．<br>*array* : 検索する配列．<br>*match* : 検索する要素の条件を定義する述語．|
|[FindAll\<*T*>(T[] *array*, Predicate<T> *match*)]()|指定された述語によって定義された条件と一致するすべての**要素**を配列で取得します．<br>*T* : 配列要素の型．<br>*array* : 検索する配列．<br>*match* : 検索する要素の条件を定義する述語．|

```C#
var arr = new[] { 0, 1, 2, 3, 2, 1, 0 };

var indexOf1 = Array.IndexOf(arr, 1);                                   // 1
var indexOf2 = Array.IndexOf(arr, 1, 3);                                // 5
var indexOf3 = Array.IndexOf(arr, 1, 3, 2);                             // -1

var lastIndexOf1 = Array.LastIndexOf(arr, 1);                           // 5
var lastIndexOf2 = Array.LastIndexOf(arr, 1, 3);                        // 1
var lastIndexOf3 = Array.LastIndexOf(arr, 1, 3, 3);                     // 1

var findIndex1 = Array.FindIndex(arr, i => i % 2 == 1);                 // 1
var findIndex2 = Array.FindIndex(arr, 3, i => i % 2 == 1);              // 3
var findIndex3 = Array.FindIndex(arr, 2, 1, i => i % 2 == 1);           // -1

var findLastIndex1 = Array.FindLastIndex(arr, i => i % 2 == 1);         // 5
var findLastIndex2 = Array.FindLastIndex(arr, 3, i => i % 2 == 1);      // 3
var findLastIndex3 = Array.FindLastIndex(arr, 2, 2, i => i % 2 == 1);   // 1

var find1 = Array.Find(arr, i => i % 2 == 1);                           // 1
var find2 = Array.Find(arr, i => i % 2 == 7);                           // 0
var findLast1 = Array.FindLast(arr, i => i % 2 == 1);                   // 1
var findLast2 = Array.FindLast(arr, i => i % 2 == 7);                   // 0
var findAll1 = Array.FindAll(arr, i => i % 2 == 1);                     // int[3] {1, 3, 5}
var findAll2 = Array.FindAll(arr, i => i % 2 == 7);                     // int[0] { }
```

###判定

|メソッド|説明|
|:---:|:---|
|[Exists\<*T*>(T[] *array*, Predicate<T> *match*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.exists?view=netcore-3.1)|指定された配列に，指定された述語によって定義された条件と一致する要素が含まれているかどうかを判断します．<br>*T* : 配列要素の型．<br>*array* : 検索する配列．<br>*match* : 検索する要素の条件を定義する述語．|
|[TrueForAll\<*T*>(T[] *array*, Predicate<T> *match*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.trueforall?view=netcore-3.1)|配列内のすべての要素が，指定された述語によって定義された条件と一致するかどうかを調べます．<br>*T* : 配列要素の型．<br>*array* : 検索する配列．<br>*match* : 検索する要素の条件を定義する述語．|

```C#
var arr = new[] { 1, 2, 3, 4, 5};

var b1 = Array.Exists(arr, i => i % 3 == 0);        // true
var b2 = Array.Exists(arr, i => i % 7 == 0);        // false

var b3 = Array.TrueForAll(arr, i => i >= 0);        // true
var b4 = Array.TrueForAll(arr, i => i % 2 == 0);    // false
```

###ソート

|メソッド|説明|
|:---:|:---|
|[Sort\<*T*>(T[] *array*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.sort?view=netcore-3.1#System_Array_Sort__1___0___)|配列のの各要素の`IComparable`実装を使用して，1次元配列全体の要素を並べ替えます．<br>*T* : 配列要素の型．<br>*array* : 並び替える1次元の配列．|
|[Sort\<*T*>(T[] *array*, int *index*, int *length*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.sort?view=netcore-3.1#System_Array_Sort__1___0___System_Int32_System_Int32_)|配列のの各要素の`IComparable`実装を使用して，配列内のある要素範囲の要素を並べ替えます．<br>*T* : 配列要素の型．<br>*array* : 並び替える1次元の配列．<br>*index* : 並べ替え対象の範囲の開始位置を示すインデックス．<br>*length* : 並べ替え対象の範囲内にある要素の数．|
|[Sort\<*TKey*,*TValue*>(TKey[] *keys*, TValue[] *items*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.sort?view=netcore-3.1#System_Array_Sort__2___0_____1___)|2つの配列オブジェクト (一方のオブジェクトがキーを格納し，他方のオブジェクトがそれらに対応する項目を格納する) を，最初の 配列内のキーに基づき，各キーによって実装された`IComparable<T>`ジェネリック インターフェイスを使用して並べ替えます．<br>*TKey *: キー用の配列要素の型．<br>*TValue* : 項目用の配列要素の型．<br>*keys* : 並べ替えるキーを格納している1次元配列．<br>*items* : *keys* 内のキーに対応する項目が格納されている1次元配列．*keys* だけを並べ替える場合は`null`．|
|[Sort\<*T*>(T[] *array*, IComparer<T> *comparer*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.sort?view=netcore-3.1#System_Array_Sort__1___0___System_Collections_Generic_IComparer___0__)|配列内の要素を，指定した`IComparer<T>`ジェネリックインターフェイスを使用して並べ替えます．<br>*T* : 配列要素の型．<br>*array* : 並び替える1次元の配列．<br>*comparer* : 要素を比較する際に使用する`IComparer<T>`ジェネリックインターフェイスの実装．各要素が実装する`IComparable<T> `ジェネリック インターフェイスを使用する場合は`null`．|
|[Sort\<*T*>(T[] *array*, int *index*, int *length*, IComparer<T> *comparer*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.sort?view=netcore-3.1#System_Array_Sort__1___0___System_Int32_System_Int32_System_Collections_Generic_IComparer___0__)|指定した `IComparer<T>`ジェネリックインターフェイスを使用して，配列内の要素の範囲内の要素を並べ替えます．<br>*T* : 配列要素の型．<br>*array* : 並び替える1次元の配列．<br>*index* : 並べ替え対象の範囲の開始位置を示すインデックス．<br>*length* : 並べ替え対象の範囲内にある要素の数．<br>*comparer* : 要素を比較する際に使用する`IComparer<T>`ジェネリックインターフェイスの実装．各要素が実装する`IComparable<T> `ジェネリック インターフェイスを使用する場合は`null`．|
|[Reverse\<*T*>(T[] *array*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.reverse?view=netcore-3.1#System_Array_Reverse__1___0___)|1 次元のジェネリック配列内の要素のシーケンスを反転させます．<br>*T* : 配列要素の型．<br>*array* : 反転する要素の1次元配列．|
|[Reverse\<*T*>(T[] *array*, int *index*, int *length*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.reverse?view=netcore-3.1#System_Array_Reverse__1___0___System_Int32_System_Int32_)|1次元のジェネリック配列内の要素のサブセットのシーケンスを反転させます．<br>*T* : 配列要素の型．<br>*array* : 反転する要素の1次元配列．<br>*index* : 反転させる対象の範囲の開始位置を示すインデックス．<br>*length* : 反転対象の範囲内にある要素の数．|

```C#
var arr1 = new[] { 3, 5, 2, 4, 1 };
Array.Sort(arr1);                               // {1, 2, 3, 4, 5}

var arr2 = new[] { 3, 5, 2, 4, 1 };
Array.Sort(arr2, 1, 3);                         // {3, 2, 4, 5, 1}

var ids = new[] { 255, 6, 0, 135, 253 };
var names = new[] { "けつばん", "アネﾞデパミﾞ", "ィ゛ゃゾ┛A", "ベアビヲ９", "ダメタマゴ" };
Array.Sort(ids, names);     // ids, names をぞれぞれ ids を Key にソート
Console.WriteLine(string.Join(", ", Enumerable.Range(0, ids.Length).Select(i => $"{ids[i]} : {names[i]}")));
// 実行結果："0 : ィ゛ゃゾ┛A, 6 : アネﾞデパミﾞ, 135 : ベアビヲ９, 253 : ダメタマゴ, 255 : けつばん"
Array.Sort(names, ids);     // ids, names をぞれぞれ names を Key にソート
Console.WriteLine(string.Join(", ", Enumerable.Range(0, ids.Length).Select(i => $"{ids[i]} : {names[i]}")));
// 実行結果："6 : アネﾞデパミﾞ, 0 : ィ゛ゃゾ┛A, 255 : けつばん, 253 : ダメタマゴ, 135 : ベアビヲ９"

var arr3 = new[] { 1, 2, 3, 4, 5 };
Array.Sort(arr3, new ReverseComparer());        // {5, 4, 3, 2, 1}

var arr4 = new[] { 1, 2, 3, 4, 5 };
Array.Sort(arr4, 1, 3, new ReverseComparer());  // {1, 4, 3, 2, 5}

var arr5 = new[] { 1, 2, 3, 4, 5 };
Array.Reverse(arr5);                            // {5, 4, 3, 2, 1}

var arr6 = new[] { 1, 2, 3, 4, 5 };
Array.Reverse(arr6, 1, 3);                      // {1, 4, 3, 2, 5}
```

```C#
/// <summary>
/// 2つのオブジェクトを入れ替える IComparer を実装します．
/// </summary>
public class ReverseComparer : IComparer
{
    int IComparer.Compare(object x, object y) => new CaseInsensitiveComparer().Compare(y, x);
}
```

###変換

|メソッド|説明|
|:---:|:---|
|[Resize\<*T*>(ref T[] *array*, int *newSize*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.resize?view=netcore-3.1)|1次元配列の要素数を，指定した新しい長さに変更します．<br>*T* : 配列要素の型．<br>*array* : サイズ変更の対象となる1次元配列．指定した長さの新しい配列を作成する場合は`null`．<br>*newSize* : 新しい配列のサイズ．|
|[ConvertAll\<*TInput*,*TOutput*> (TInput[] *array*, Converter<TInput,TOutput> *converter*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.convertall?view=netcore-3.1)|ある型の配列を別の型の配列に変換します．<br>*TInput* : 元の配列要素の型．<br>*TOutput* : 変換後の配列要素の型．<br>*array* : 変換元の1次元配列．<br>*converter* : 各要素の型を変換するための方法．|
|[AsReadOnly\<*T*>(T[] *array*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.asreadonly?view=netcore-3.1)|指定した配列をラップする読み取り専用のラッパー`ReadOnlyCollection<T>`を作成します．<br>*T* : 配列要素の型．<br>*array* : ラップする1次元配列．|
|[AsMemory\<*T*>(**this** T[] *array*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.memoryextensions.asmemory?view=netcore-3.1#System_MemoryExtensions_AsMemory__1___0___)|挿入先の配列に新しいメモリ領域を作成します．<br>*T* : 配列要素の型．<br>*array* : 変換する配列．|
|[AsSpan\<*T*>(**this** T[] *array*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.memoryextensions.asspan?view=netcore-3.1#System_MemoryExtensions_AsSpan__1___0___)|挿入先の配列に新しいスパンを作成します．<br>*T* : 配列要素の型．<br>*array* : 変換する配列．|

```C#
var arr1 = new[] { 1, 2, 3, 4, 5 };
Array.Resize(ref arr1, 3);  // {1, 2, 3}
Array.Resize(ref arr1, 5);  // {1, 2, 3, 0, 0}

int[] arr2 = null;
Array.Resize(ref arr2, 3);  // {0, 0, 0}

var rc = Array.AsReadOnly(arr1);        // System.Collections.ObjectModel.ReadOnlyCollection<int> {1, 2, 3, 0, 0}
var span = arr1.AsSpan()[1..^1];        // System.Span<int>   : [0]|2, [1]|3, [2]|0
var memory = arr1.AsMemory()[1..^1];    // System.Memory<int> : [0]|2, [1]|3, [2]|0
```

###実行

|メソッド|説明|
|:---:|:---|
|[ForEach\<*T*>(T[] *array*, Action<T> *action*)](https://docs.microsoft.com/ja-jp/dotnet/api/system.array.foreach?view=netcore-3.1)|指定された配列内の各要素に対して，指定された処理を実行します．<br>*T* : 配列要素の型．<br>*array* : 要素に処理を適用する配列．<br>*action* : 配列の各要素に対して実行する`Action<T>`．|

```C#
var pieces = new[] { new[] { "香", "桂", "銀", "金", "玉", "金", "銀", "桂" , "香" },
                     new[] { "　", "飛", "　", "　", "　", "　", "　", "角" , "　" },
                     new[] { "歩", "歩", "歩", "歩", "歩", "歩", "歩", "歩" , "歩" },
                     new[] { "　", "　", "　", "　", "　", "　", "　", "　" , "　" },
                     new[] { "　", "　", "　", "　", "　", "　", "　", "　" , "　" },
                     new[] { "　", "　", "　", "　", "　", "　", "　", "　" , "　" },
                     new[] { "歩", "歩", "歩", "歩", "歩", "歩", "歩", "歩" , "歩" },
                     new[] { "　", "角", "　", "　", "　", "　", "　", "飛" , "　" },
                     new[] { "香", "桂", "銀", "金", "王", "金", "銀", "桂" , "香" } };
Array.ForEach(pieces, row => Console.WriteLine(string.Join(string.Empty, row)));
```


```C#:実行結果
香桂銀金玉金銀桂香
　飛　　　　　角　
歩歩歩歩歩歩歩歩歩
　　　　　　　　　
　　　　　　　　　
　　　　　　　　　
歩歩歩歩歩歩歩歩歩
　角　　　　　飛　
香桂銀金王金銀桂香
```

##参考
- [配列 - C# プログラミング ガイド | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/system.array?view=netcore-3.1)
- [Array クラス (System) | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/system.array?view=netcore-3.1)
- [インデックス/範囲処理 - C# によるプログラミング入門 | ++C++; // 未確認飛行 C](https://ufcpp.net/study/csharp/data/dataranges/)
- [将トレ 棋士・藤井聡太の将棋トレーニング 公式サイト](https://www.sho-tore.jp/?utm_source=google&utm_medium=cpc&utm_campaign=search&yclid=YSS.EAIaIQobChMI3IKw8tvY6gIVR6qWCh3c8AZPEAAYASAAEgKgKfD_BwE)
- [バグポケモン一覧 - ポケモンWiki](https://wiki.ポケモン.com/wiki/%E3%83%90%E3%82%B0%E3%83%9D%E3%82%B1%E3%83%A2%E3%83%B3%E4%B8%80%E8%A6%A7)

[^1]: 本稿では，`System.Array`由来の機能の内，主要なものについて取り扱う．また，`System.Linq`による拡張メソッドについては別記事で纏めることにする．

[^2]: シャローコピー[shallow copy=浅いコピー．簡易コピーとも呼ばれる] では，変数などのオブジェクトに入っている値をそのままコピー先に複製する．コピーするデータが値型の場合は特に問題はないが，参照型の場合は**参照先アドレス**の複製になるので，複製元オブジェクトと複製先オブジェクトが同じ場所を参照している状態になる．