.NETにおける配列はArrayクラスを基本クラスとしていて、すべての配列は暗黙的にこのクラスを継承しています。 配列の基本的な機能はすべてこのクラスにより提供されます。 また、Arrayクラスには様々なメソッドが用意されていて、それらを使うことで言語の構文では用意されていない配列操作などを行うことが出来ます。

ここで解説する配列の操作と、対応するArrayクラスのメソッドを表にまとめます。 個々のメソッドの詳細については順に解説していきます。

配列操作と対応するArrayクラスのメソッド
配列操作 対応するArrayクラスのメソッド 解説へのリンク
配列をクリアする Clear 解説へ
配列を同じ値で埋める Fill 解説へ
配列のサイズ(長さ)を変更する Resize 解説へ
配列を読み取り専用にする AsReadOnly 解説へ
コピー
(複製・複写)
配列の複製を作成する Clone 解説へ
配列の一部・全部を他の配列に複写する Copy, CopyTo 解説へ
並べ替え 配列内の要素を逆順に(リバース)する Reverse 解説へ
配列内の要素をソートする Sort 解説へ
要素の検索 配列内にある要素を検索してインデックスを取得する IndexOf, LastIndexOf, BinarySearch 解説へ
述語(Predicate)を使って配列内の要素を検索する Find, FindLast, FindAll, FindIndex, FindLastIndex,Exists, TrueForAll 解説へ
全要素に対する操作 配列内の全要素を他の型・値に変換する ConvertAll 解説へ
配列内の全要素を列挙する ForEach 解説へ
構文によらない配列の操作を行う CreateInstance, GetValue, SetValue 解説へ
配列操作 対応するArrayクラスのメソッド 解説へのリンク

クリア (Clear)

Array.Clearメソッドを使うことで、配列内の要素をクリアして初期化することが出来ます。 このメソッドを使って配列内をクリアすると、配列内の各要素にデフォルト値が設定されます。 デフォルト値は型によって異なりますが、数値などの型では0や0に相当する値、文字列型を含む参照型ではヌル参照(null/Nothing)となります。

どのような値で初期化されるか、型とデフォルト値の詳細については型の種類・サイズ・精度・値域 §.型のデフォルト値を参照してください。

また、このメソッドは引数としてクリアを開始するインデックスと長さをとるため、配列の一部分だけをクリアすることも出来ます。

Array.Clearメソッドで1次元配列をゼロクリアする
using System;

class Sample {
  static void Main()
  {
    int[] arr = {0, 1, 2, 3, 4};

    // インデックスが3の要素から2個分をクリア
    Array.Clear(arr, 3, 2);

    foreach (var elem in arr) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();

    // 配列の全要素をクリア
    Array.Clear(arr, 0, arr.Length);

    foreach (var elem in arr) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();
  }
}
Array.Clearメソッドで1次元配列をゼロクリアする
Imports System

Class Sample
  Shared Sub Main()
    Dim arr() As Integer = {0, 1, 2, 3, 4}

    ' インデックスが3の要素から2個分をクリア
    Array.Clear(arr, 3, 2)

    For Each elem As Integer In arr
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()

    ' 配列の全要素をクリア
    Array.Clear(arr, 0, arr.Length)

    For Each elem As Integer In arr
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
0, 1, 2, 0, 0, 
0, 0, 0, 0, 0, 

なお、Array.Clearメソッドは配列内の要素をクリアするためのもので、配列の長さを0にするものではありません。 配列の長さを0にするにはResizeメソッドを使います。

Array.Clearメソッドは、0を指定したmemset、あるいはZeroMemoryマクロのような動作となります。 Array.Clearメソッドでは配列を0以外の値にクリアする事はできません。 配列全体を0以外の同一の値にセットする、memsetFillMemoryマクロのような動作を求める場合は、Array.Fillメソッドを使用するか、for文等を使って個別に実装する必要があります。

ジャグ配列・多次元配列のクリア

Array.Clearメソッドでジャグ配列をクリアする場合は、ジャグ配列の1段目に格納されている配列がクリアされヌル参照(null/Nothing)の状態になります。 ジャグ配列に格納されている各配列はクリアされません。

Array.Clearメソッドで2段のジャグ配列をゼロクリアする
using System;

class Sample {
  static void Main()
  {
    // ジャグ配列に格納する配列
    int[] arr1 = {0, 1, 2, 3, 4};
    int[] arr2 = {5, 6, 7};

    // 2段のジャグ配列
    int[][] jagged = {
      arr1,
      arr2,
    };

    // ジャグ配列をクリア
    Array.Clear(jagged, 0, jagged.Length);

    Console.WriteLine("jagged[0] == null : {0}", jagged[0] == null);
    Console.WriteLine("jagged[1] == null : {0}", jagged[1] == null);

    foreach (var elem in arr1) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();
  }
}
実行結果
jagged[0] == null : True
jagged[1] == null : True
0, 1, 2, 3, 4, 
Array.Clearメソッドで2段のジャグ配列をゼロクリアする
Imports System

Class Sample
  Shared Sub Main()
    ' ジャグ配列に格納する配列
    Dim arr1() As Integer = {0, 1, 2, 3, 4}
    Dim arr2() As Integer = {5, 6, 7}

    ' 2段のジャグ配列
    Dim jagged()() As Integer = { _
      arr1, _
      arr2 _
    }

    ' ジャグ配列をクリア
    Array.Clear(jagged, 0, jagged.Length)

    Console.WriteLine("jagged(0) Is Nothing : {0}", jagged(0) Is Nothing)
    Console.WriteLine("jagged(1) Is Nothing : {0}", jagged(1) Is Nothing)

    For Each elem As Integer In arr1
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
jagged(0) Is Nothing : True
jagged(1) Is Nothing : True
0, 1, 2, 3, 4,

一方、Array.Clearメソッドでは多次元配列をクリアすることも出来ますが、その際多次元配列は1次元配列の様に扱われます。 Array.Clearメソッドの引数に指定するインデックスは、多次元配列を1次元配列に展開したときの位置として解釈されるという点に注意が必要です。

Array.Clearメソッドで2次元配列をゼロクリアする
using System;

class Sample {
  static void Main()
  {
    int[,] matrix = {
      {0, 1, 2, 3},
      {4, 5, 6, 7},
      {8, 9, 10, 11},
    };

    // 2次元配列全体の3番目の要素から4個分をクリア
    Array.Clear(matrix, 3, 4);

    for (var d1 = 0; d1 < matrix.GetLength(0); d1++) {
      for (var d2 = 0; d2 < matrix.GetLength(1); d2++) {
        Console.Write("{0}, ", matrix[d1, d2]);
      }
      Console.WriteLine();
    }
  }
}
Array.Clearメソッドで2次元配列をゼロクリアする
Imports System

Class Sample
  Shared Sub Main()
    Dim matrix As Integer(,) = { _
      {0, 1, 2, 3}, _
      {4, 5, 6, 7}, _
      {8, 9, 10, 11} _
    }

    ' 2次元配列の一部分をクリア
    Array.Clear(matrix, 3, 4)

    For d1 As Integer = 0 To matrix.GetLength(0) - 1
      For d2 As Integer = 0 To matrix.GetLength(1) - 1
        Console.Write("{0}, ", matrix(d1, d2))
      Next
      Console.WriteLine()
    Next
  End Sub
End Class
実行結果
0, 1, 2, 0, 
0, 0, 0, 7, 
8, 9, 10, 11,

同じ値で埋める (Fill)

Array.Fillメソッドを用いることで、配列内のすべての要素を同じ値に設定することができます。 Array.Clearメソッドが配列内すべてを0に設定するのに対して、Fillメソッドでは任意の値に設定することができます。 また、Clearメソッドと同様に、配列内の範囲を指定してその要素だけを同じ値に設定することもできます。 Array.Fillメソッドは.NET Standard 2.1/.NET Core 2.0以降で使用できます。

Array.Fillメソッドで配列を同じ値で埋める .NET Standard 2.1/.NET Core 2.0
using System;

class Sample {
  static void Main()
  {
    int[] arr = {0, 1, 2, 3, 4};

    // 配列の全要素を-1に設定する
    Array.Fill(arr, -1);

    foreach (var elem in arr) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();

    // インデックスが1の要素から3個分を9に設定する
    Array.Fill(arr, 9, 1, 3);

    foreach (var elem in arr) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();
  }
}
Array.Fillメソッドで配列を同じ値で埋める .NET Standard 2.1/.NET Core 2.0
Imports System

Class Sample
  Shared Sub Main()
    Dim arr() As Integer = {0, 1, 2, 3, 4}

    ' 配列の全要素を-1に設定する
    Array.Fill(arr, -1)

    For Each elem As Integer In arr
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()

    ' インデックスが1の要素から3個分を9に設定する
    Array.Fill(arr, 9, 1, 3)

    For Each elem As Integer In arr
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
-1, -1, -1, -1, -1, 
-1, 9, 9, 9, -1, 

Array.Clearメソッドは二次元以上の配列にも対応していますが、Array.Fillメソッドは一次元配列のみに対応しています。

リサイズ (Resize)

Array.Resizeメソッドを使うことで、配列の長さを変更することが出来ます。 このメソッドによってリサイズされるというのは見た目の動作で、実際には、変更後のサイズの配列が新たに作成され、その配列に元の配列の内容をコピーしたものが引数で指定した配列と置き換えられるという動作になります。 このメソッドでは、配列の長さを元の長さよりも短くすることも長くすることも可能です。 Array.Resizeメソッドで配列を拡張した場合、拡張した部分にはデフォルト値がセットされます。

Array.Resizeメソッドで配列をリサイズする
using System;

class Sample {
  static void Main()
  {
    int[] arr = {0, 1, 2, 3, 4};

    // 配列の長さを長くする
    Array.Resize(ref arr, 7);

    foreach (var elem in arr) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();

    // 配列の長さを短くする
    Array.Resize(ref arr, 3);

    foreach (var elem in arr) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();
  }
}
Array.Resizeメソッドで配列をリサイズする
Imports System

Class Sample
  Shared Sub Main()
    Dim arr() As Integer = {0, 1, 2, 3, 4}

    ' 配列の長さを長くする
    Array.Resize(arr, 7)

    For Each elem As Integer In arr
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()

    ' 配列の長さを短くする
    Array.Resize(arr, 3)

    For Each elem As Integer In arr
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
0, 1, 2, 3, 4, 0, 0, 
0, 1, 2, 

ジャグ配列をリサイズすることも出来ますが、その場合は1段目の長さのみが変更できます。 2段目以降の長さを変更する場合は、格納されている配列に対して個別にArray.Resizeメソッドを呼び出してリサイズする必要があります。

なお、Array.Resizeメソッドでは多次元配列のサイズを変更することは出来ません。

複製・複写

複製 (Clone)

Array.Cloneメソッドを使うことで、配列を複製して同じ内容を持った配列を生成することが出来ます。 Array.Cloneメソッドの戻り値はobjectであるため、必要に応じて複製元と同じ型にキャストして使います。

Array.Cloneメソッドで1次元配列の複製を作成する
using System;

class Sample {
  static void Main()
  {
    int[] arr1 = {0, 1, 2, 3, 4};
    int[] arr2;

    // arr1を複製してarr2に代入
    arr2 = (int[])arr1.Clone();

    // 複製元と複製後の配列の要素を変更
    arr1[2] = 0;
    arr2[2] = 5;

    // それぞれの配列の内容を表示
    foreach (var elem in arr1) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();

    foreach (var elem in arr2) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();
  }
}
Array.Cloneメソッドで1次元配列の複製を作成する
Imports System

Class Sample
  Shared Sub Main()
    Dim arr1() As Integer = {0, 1, 2, 3, 4}
    Dim arr2() As Integer

    ' arr1を複製してarr2に代入
    arr2 = DirectCast(arr1.Clone(), Integer())

    ' 複製元と複製後の配列の要素を変更
    arr1(2) = 0
    arr2(2) = 5

    ' それぞれの配列の内容を表示
    For Each elem As Integer In arr1
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()

    For Each elem As Integer In arr2
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
0, 1, 0, 3, 4, 
0, 1, 5, 3, 4, 

このメソッドでは簡易コピーが行われるため、参照型を要素に持つ配列では参照のみがコピーされます。 そのため、ジャグ配列の複製を行うと、複製元と複製後のジャグ配列内における2段目以降はどちらも同一のインスタンスを参照する事になります。

Cloneメソッドと簡易コピーについてより詳しくはオブジェクトの複製で解説しています。


多次元配列を複製する場合の結果は1次元配列を複製する場合と同様で、長さ・次元数・格納される要素が同一の多次元配列が生成されます。

Array.Cloneメソッドで2次元配列の複製を作成する
using System;

class Sample {
  static void Main()
  {
    int[,] matrix1 = {
      {0, 1, 2, 3},
      {4, 5, 6, 7},
      {8, 9, 10, 11},
    };
    int[,] matrix2;

    // matrix1を複製してmatrix2に代入
    matrix2 = (int[,])matrix1.Clone();

    // 複製元と複製後の配列の要素を変更
    matrix1[0, 0] = 99;
    matrix2[0, 0] = -1;

    // それぞれの配列の内容を表示
    for (var d1 = 0; d1 < matrix1.GetLength(0); d1++) {
      for (var d2 = 0; d2 < matrix1.GetLength(1); d2++) {
        Console.Write("{0}, ", matrix1[d1, d2]);
      }
      Console.WriteLine();
    }
    Console.WriteLine();

    for (var d1 = 0; d1 < matrix2.GetLength(0); d1++) {
      for (var d2 = 0; d2 < matrix2.GetLength(1); d2++) {
        Console.Write("{0}, ", matrix2[d1, d2]);
      }
      Console.WriteLine();
    }
  }
}
Array.Cloneメソッドで2次元配列の複製を作成する
Imports System

Class Sample
  Shared Sub Main()
    Dim matrix1 As Integer(,) = { _
      {0, 1, 2, 3}, _
      {4, 5, 6, 7}, _
      {8, 9, 10, 11} _
    }
    Dim matrix2 As Integer(,)

    ' matrix1を複製してmatrix2に代入
    matrix2 = DirectCast(matrix1.Clone(), Integer(,))

    ' 複製元と複製後の配列の要素を変更
    matrix1(0, 0) = 99
    matrix2(0, 0) = -1

    ' それぞれの配列の内容を表示
    For d1 As Integer = 0 To matrix1.GetLength(0) - 1
      For d2 As Integer = 0 To matrix1.GetLength(1) - 1
        Console.Write("{0}, ", matrix1(d1, d2))
      Next
      Console.WriteLine()
    Next
    Console.WriteLine()

    For d1 As Integer = 0 To matrix2.GetLength(0) - 1
      For d2 As Integer = 0 To matrix2.GetLength(1) - 1
        Console.Write("{0}, ", matrix2(d1, d2))
      Next
      Console.WriteLine()
    Next
  End Sub
End Class
実行結果
99, 1, 2, 3, 
4, 5, 6, 7, 
8, 9, 10, 11, 

-1, 1, 2, 3, 
4, 5, 6, 7, 
8, 9, 10, 11, 

複写 (Copy, CopyTo)

Copyメソッド

Array.Copyメソッドは、Array.Cloneメソッドとは異なり配列の内容を既に存在する別の配列に複写します。 引数で複写する長さ(要素数)を指定できるので、配列の途中までをコピーするということも出来ます。 当然、複写先の配列は複写元と同じがそれ以上の長さを持っている必要があります。 Array.Copyメソッドも、Array.Cloneメソッドと同様要素の簡易コピーを行います。

Array.Copyメソッドで1次元配列を別の配列に複写する
using System;

class Sample {
  static void Main()
  {
    // 複写元の配列
    int[] arr1 = {0, 1, 2, 3, 4};

    // 初期化されていない配列を確保
    var arr2 = new int[5];

    foreach (var elem in arr2) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();

    // arr1の要素の先頭から3個分をarr2に複写
    Array.Copy(arr1, arr2, 3);

    foreach (var elem in arr2) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();

    // arr1の全要素をarr2に複写
    Array.Copy(arr1, arr2, arr1.Length);

    foreach (var elem in arr2) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();
  }
}
Array.Copyメソッドで1次元配列を別の配列に複写する
Imports System

Class Sample
  Shared Sub Main()
    ' 複写元の配列
    Dim arr1() As Integer = {0, 1, 2, 3, 4}

    ' 初期化されていない配列を確保
    Dim arr2(4) As Integer

    For Each elem As Integer In arr2
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()

    ' arr1の要素の先頭から3個分をarr2に複写
    Array.Copy(arr1, arr2, 3)

    For Each elem As Integer In arr2
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()

    ' arr1の全要素をarr2に複写
    Array.Copy(arr1, arr2, arr1.Length)

    For Each elem As Integer In arr2
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
0, 0, 0, 0, 0, 
0, 1, 2, 0, 0, 
0, 1, 2, 3, 4, 

配列のバイト表現を別の配列へ転写する目的(バイト列としてのコピー)にはBuffer.BlockCopyメソッドを使うことができます。 詳しくはバイト列操作 §.BlockCopyメソッドを参照してください。

Array.Copyメソッドは、複写元と複写先に同じ配列を指定することができます。 またArray.Copyメソッドの動作は、memcpyではなくmemmove相当の動作になります。 詳しくは§.同一配列への複写を参照してください。


Array.Copyメソッドでは、複写する長さだけでなく、複写元と複写先の始点となるインデックスを指定して複写することも出来ます。 Arrayクラスには部分配列を抜き出すArray.Sliceのようなメソッドは用意されていませんが、次の例のように配列の生成と部分配列の複写を行うことで、Array.Slice相当の処理を行うことが出来ます。

Array.Copyメソッドで部分配列の複写を行い抽出する
using System;

class Sample {
  static void Main()
  {
    // 複写元の配列
    int[] arr1 = {0, 1, 2, 3, 4};

    // 初期化されていない配列を確保
    var arr2 = new int[3];

    // arr1の部分配列(インデックス2から3個分)をarr2のインデックス0以降に複写
    Array.Copy(arr1, 2, arr2, 0, 3);

    foreach (var elem in arr2) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();
  }
}
Array.Copyメソッドで部分配列の複写を行い抽出する
Imports System

Class Sample
  Shared Sub Main()
    ' 複写元の配列
    Dim arr1() As Integer = {0, 1, 2, 3, 4}

    ' 初期化されていない配列を確保
    Dim arr2(2) As Integer

    ' arr1の部分配列(インデックス2から3個分)をarr2のインデックス0以降に複写
    Array.Copy(arr1, 2, arr2, 0, 3)

    For Each elem As Integer In arr2
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
2, 3, 4, 

この方法では部分配列を取得するために新たな配列インスタンスの作成と複写を行うことになりますが、ArraySegmentを使えばインスタンス生成や複写を行わずに部分配列のビューを取得・作成することもできます。

C# 8.0以降、.NET Core 3.0以降では、インデックス/範囲構文n..mを使うことで部分配列の抽出を行うことができるようになっています。

インデックス範囲構文を使って部分配列を抽出する  .NET Standard 2.1/.NET Core 3.0
using System;

class Sample {
  static void Main()
  {
    // 複写元の配列
    int[] arr1 = {0, 1, 2, 3, 4};

    // arr1の部分配列(インデックス2から5より前まで、2以上5未満の3個分)をarr2として抽出
    var arr2 = arr1[2..5];

    foreach (var elem in arr2) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();
  }
}
実行結果
2, 3, 4,

部分配列の取得と同様に、配列の連結を行うArray.Concatのようなメソッドも用意されていませんが、次の例のように連結後の配列の生成と連結元の配列の複写を行うことで、Array.Concat相当の処理を行うことが出来ます。

Array.Copyメソッドで配列を連結する
using System;

class Sample {
  static void Main()
  {
    // 連結元の配列
    int[] arr1 = {0, 1, 2, 3, 4};
    int[] arr2 = {5, 6, 7};

    // 連結後の配列となる、初期化されていない配列を確保
    var arr3 = new int[arr1.Length + arr2.Length];

    // arr1の内容をarr3の先頭に複写
    Array.Copy(arr1, 0, arr3, 0, arr1.Length);

    // arr2の内容をarr3の続きに複写
    Array.Copy(arr2, 0, arr3, arr1.Length, arr2.Length);

    foreach (var elem in arr3) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();
  }
}
Array.Copyメソッドで配列を連結する
Imports System

Class Sample
  Shared Sub Main()
    ' 連結元の配列
    Dim arr1() As Integer = {0, 1, 2, 3, 4}
    Dim arr2() As Integer = {5, 6, 7}

    ' 連結後の配列となる、初期化されていない配列を確保
    Dim arr3(arr1.Length + arr2.Length - 1) As Integer

    ' arr1の内容をarr3の先頭に複写
    Array.Copy(arr1, 0, arr3, 0, arr1.Length)

    ' arr2の内容をarr3の続きに複写
    Array.Copy(arr2, 0, arr3, arr1.Length, arr2.Length)

    For Each elem As Integer In arr3
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
0, 1, 2, 3, 4, 5, 6, 7, 

多次元配列の複写

多次元配列もArray.Copyメソッドで複写できます。 多次元配列を複写する場合は、次元数が同じで複写先の長さが十分であれば、複写元と複写先で次元毎の長さが異なっていても複写することが出来ます。

Array.Copyメソッドで2次元配列を複写する
using System;

class Sample {
  static void Main()
  {
    // 複写元の2次元配列(長さが4×3)
    int[,] matrix1 = {
      {0, 1, 2, 3},
      {4, 5, 6, 7},
      {8, 9, 10, 11},
    };

    // 複写先の2次元配列(長さが3×5)を確保
    var matrix2 = new int[5, 3];

    // 配列を複写
    Array.Copy(matrix1, matrix2, matrix1.Length);

    // それぞれの配列の内容を表示
    Print(matrix1);

    Console.WriteLine();

    Print(matrix2);
  }

  static void Print(int[,] matrix)
  {
    for (var d1 = 0; d1 < matrix.GetLength(0); d1++) {
      for (int d2 = 0; d2 < matrix.GetLength(1); d2++) {
        Console.Write("{0}, ", matrix[d1, d2]);
      }
      Console.WriteLine();
    }
  }
}
Array.Copyメソッドで2次元配列を複写する
Imports System

Class Sample
  Shared Sub Main()
    ' 複写元の2次元配列(長さが4×3)
    Dim matrix1 As Integer(,) = { _
      {0, 1, 2, 3}, _
      {4, 5, 6, 7}, _
      {8, 9, 10, 11} _
    }

    ' 複写先の2次元配列(長さが3×5)を確保
    Dim matrix2(4, 2) As Integer

    ' 配列を複写
    Array.Copy(matrix1, matrix2, matrix1.Length)

    ' それぞれの配列の内容を表示
    Print(matrix1)

    Console.WriteLine()

    Print(matrix2)
  End Sub

  Shared Sub Print(ByVal matrix As Integer(,))
    For d1 As Integer = 0 To matrix.GetLength(0) - 1
      For d2 As Integer = 0 To matrix.GetLength(1) - 1
        Console.Write("{0}, ", matrix(d1, d2))
      Next
      Console.WriteLine()
    Next
  End Sub
End Class
実行結果
0, 1, 2, 3, 
4, 5, 6, 7, 
8, 9, 10, 11, 

0, 1, 2, 
3, 4, 5, 
6, 7, 8, 
9, 10, 11, 
0, 0, 0, 

Copyメソッドでは次元数が異なる配列への複写が出来ないので、そういった場合はfor文・foreach文を使って要素を一つずつコピーする必要があります。

1次元配列から2次元配列へ複写する
using System;

class Sample {
  static void Main()
  {
    // 複写元の1次元配列(長さが12)
    int[] matrix1 = {
      0, 1, 2, 3,
      4, 5, 6, 7,
      8, 9, 10, 11,
    };

    // 複写先の2次元配列(長さが4×3)を確保
    var matrix2 = new int[3, 4];

    // 配列を複写
    for (var i = 0; i < matrix1.Length; i++) {
      int d1 = i / matrix2.GetLength(1);
      int d2 = i % matrix2.GetLength(1);

      matrix2[d1, d2] = matrix1[i];
    }

    // 結果を表示
    for (var d1 = 0; d1 < matrix2.GetLength(0); d1++) {
      for (var d2 = 0; d2 < matrix2.GetLength(1); d2++) {
        Console.Write("{0}, ", matrix2[d1, d2]);
      }
      Console.WriteLine();
    }
  }
}
1次元配列から2次元配列へ複写する
Imports System

Class Sample
  Shared Sub Main()
    ' 複写元の1次元配列(長さが12)
    Dim matrix1 As Integer() = { _
      0, 1, 2, 3, _
      4, 5, 6, 7, _
      8, 9, 10, 11 _
    }

    ' 複写先の2次元配列(長さが4×3)を確保
    Dim matrix2(2, 3) As Integer

    ' 配列を複写
    For i As Integer = 0 To matrix1.Length - 1
      Dim d1 As Integer = i \ matrix2.GetLength(1)
      Dim d2 As Integer = i Mod matrix2.GetLength(1)

      matrix2(d1, d2) = matrix1(i)
    Next

    ' 結果を表示
    For d1 As Integer = 0 To matrix2.GetLength(0) - 1
      For d2 As Integer = 0 To matrix2.GetLength(1) - 1
        Console.Write("{0}, ", matrix2(d1, d2))
      Next
      Console.WriteLine()
    Next
  End Sub
End Class
実行結果
0, 1, 2, 3, 
4, 5, 6, 7, 
8, 9, 10, 11, 

同一配列への複写

Array.Copyメソッドでは、複写先を複写元と同一の配列にすることが出来ます。 この際、複写先と複写元の一部が重なっていても問題なく複写されます。

Array.Copyメソッドで配列自身へ複写する
using System;

class Sample {
  static void Main()
  {
    // 複写元の配列
    int[] arr = {0, 1, 2, 3, 4};

    // arrの部分配列(インデックス0から3個分)をarr自身のインデックス2以降にコピー
    Array.Copy(arr, 0, arr, 2, 3);

    foreach (var elem in arr) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();
  }
}
Array.Copyメソッドで配列自身へ複写する
Imports System

Class Sample
  Shared Sub Main()
    ' 複写元の配列
    Dim arr() As Integer = {0, 1, 2, 3, 4}

    ' arrの部分配列(インデックス0から3個分)をarr自身のインデックス2以降にコピー
    Array.Copy(arr, 0, arr, 2, 3)

    For Each elem As Integer In arr
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
0, 1, 0, 1, 2, 

このように、Array.Copyメソッドはmemcpyではなくmemmoveに相当する動作となります。

異なる型の配列への複写

複写元と複写先の型に互換性がある場合、もしくは型が複写元と複写先がどちらもプリミティブ型で複写が拡大変換となる場合に限り、異なる型の配列へ複写することが出来ます。

例えば、次の例のように、ともにプリミティブ型であり拡大変換となるint型配列からlong型配列への複写は正常に行われます。

Array.Copyメソッドで異なる型の配列へ複写する
using System;

class Sample {
  static void Main()
  {
    // 複写元の配列 (int型)
    int[] source = {0, 1, 2, 3, 4};

    // 複写先の配列 (long型)
    var dest = new long[5];

    // int型の配列をlong型の配列に複写
    Array.Copy(source, dest, 5);

    foreach (var elem in dest) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();
  }
}
Array.Copyメソッドで異なる型の配列へ複写する
Imports System

Class Sample
  Shared Sub Main()
    ' 複写元の配列 (Integer型)
    Dim source() As Integer = {0, 1, 2, 3, 4}

    ' 複写先の配列 (Long型)
    Dim dest(4) As Long

    ' Integer型の配列をLong型の配列に複写
    Array.Copy(source, dest, 5)

    For Each elem As Long In dest
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
0, 1, 2, 3, 4, 

先に挙げた以外の場合、すなわち型に互換性がない、どちらもプリミティブ型でない、型の変換が縮小変換となるのいずれかの場合では、例外ArrayTypeMismatchExceptionがスローされます。

例えば、上記の例を逆にしてlong型配列からint型配列に複写しようとする場合、どちらの型もプリミティブではあってもlongからintへは縮小変換となるため、ArrayTypeMismatchExceptionがスローされます。

型の分類、プリミティブ型については型の種類・サイズ・精度・値域、拡大変換・縮小変換については基本型の型変換で詳しく解説しています。

Buffer.BlockCopyメソッドでは、プリミティブ型であれば縮小変換となるような配列へのコピーも行うことができます。 詳しくはバイト列操作 §.BlockCopyメソッドを参照してください。

CopyToメソッド

Array.Copyメソッドの他にも、Array.CopyToメソッドを使って複写することも出来ます。 このメソッドはArray.Copyとは異なりインスタンスメソッドです。 また、引数に指定するのは複写先の始点となるインデックスで、常に複写元の配列全体が複写されます。

Array.CopyToメソッドを使って配列の内容を複写する
using System;

class Sample {
  static void Main()
  {
    // 複写元の配列
    int[] arr1 = {0, 1, 2, 3, 4};

    // 初期化されていない配列を確保
    var arr2 = new int[7];

    // arr1の全要素をarr2のインデックス1以降に複写
    arr1.CopyTo(arr2, 1);

    foreach (var elem in arr2) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();
  }
}
Array.CopyToメソッドを使って配列の内容を複写する
Imports System

Class Sample
  Shared Sub Main()
    ' 複写元の配列
    Dim arr1() As Integer = {0, 1, 2, 3, 4}

    ' 初期化されていない配列を確保
    Dim arr2(6) As Integer

    ' arr1の全要素をarr2のインデックス1以降に複写
    arr1.CopyTo(arr2, 1)

    For Each elem As Integer In arr2
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
0, 0, 1, 2, 3, 4, 0, 

CopyToはインスタンスメソッドであるという点以外は、Copyメソッドと同様で、その動作もCopyメソッドと同じです。

配列の作成・要素の取得と設定 (CreateInstance, GetValue, SetValue)

言語で用意されている構文を使う他に、Array.CreateInstanceメソッドを使うことで任意の型・任意の長さの配列を作成することが出来ます。 このメソッドの戻り値はArrayクラスとなるので、必要に応じて適切な配列型にキャストしてから使います。 このメソッドで作成した配列は、通常の構文で作成した配列と何ら変わりありません。

また、Array.GetValueメソッドおよびArray.SetValueメソッドを使うことで、配列の各要素にアクセスするための構文(インデクサ)を使用せずに配列に値を取得・設定することが出来ます。 このメソッドは配列の型・次元がどのようなものでも値を取得・設定することが出来ます。

Arrayクラスのメソッドを使って配列の作成と要素の取得・設定を行う (CreateInstance, GetValue, SetValue)
using System;

class Sample {
  static void Main()
  {
    // 型がintで長さが5の配列を作成
    var arr1 = (int[])Array.CreateInstance(typeof(int), 5);

    arr1[0] = 0;
    arr1[1] = 1;
    arr1[2] = 2;
    arr1[3] = 3;
    arr1[4] = 4;

    foreach (var elem in arr1) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();
    Console.WriteLine();

    // 型がstringで長さが3の配列を作成
    var arr2 = Array.CreateInstance(typeof(string), 3);

    // SetValueメソッドを使って値を設定
    arr2.SetValue("Alice", 0);    // 配列のインデックス0に文字列"Alice"を設定
    arr2.SetValue("Bob", 1);      // 配列のインデックス1に文字列"Bob"を設定
    arr2.SetValue("Charlie", 2);  // 配列のインデックス2に文字列"Charlie"を設定

    // GetValueメソッドを使って値を取得
    for (var i = 0; i < arr2.Length; i++) {
      Console.WriteLine("arr2[{0}] = {1}", i, arr2.GetValue(i));
    }
  }
}
Arrayクラスのメソッドを使って配列の作成と要素の取得・設定を行う (CreateInstance, GetValue, SetValue)
Imports System

Class Sample
  Shared Sub Main()
    ' 型がIntegerで長さが5の配列を作成
    Dim arr1() As Integer = DirectCast(Array.CreateInstance(GetType(Integer), 5), Integer())

    arr1(0) = 0
    arr1(1) = 1
    arr1(2) = 2
    arr1(3) = 3
    arr1(4) = 4

    For Each elem As Integer In arr1
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()
    Console.WriteLine()

    ' 型がStringで長さが3の配列を作成
    Dim arr2 As Array = Array.CreateInstance(GetType(String), 3)

    ' SetValueメソッドを使って値を設定
    arr2.SetValue("Alice", 0)   ' 配列のインデックス0に文字列"Alice"を設定
    arr2.SetValue("Bob", 1)     ' 配列のインデックス1に文字列"Bob"を設定
    arr2.SetValue("Charlie", 2) ' 配列のインデックス2に文字列"Charlie"を設定

    ' GetValueメソッドを使って値を取得
    For i As Integer = 0 To arr2.Length - 1
      Console.WriteLine("arr2({0}) = {1}", i, arr2.GetValue(i))
    Next
  End Sub
End Class
実行結果
0, 1, 2, 3, 4, 

arr2(0) = Alice
arr2(1) = Bob
arr2(2) = Charlie

GetValueメソッド・SetValueメソッドは要素単位で値の取得・設定を行います。 バイト単位で配列内の値を取得・設定したい場合はBuffer.GetByteメソッドBuffer.SetByteメソッドを使うことができます。 詳しくはバイト列操作 §.バイト単位での値の設定・取得 (GetByteメソッド・SetByteメソッド)を参照してください。


Array.CreateInstance, Array.GetValue, Array.SetValueの各メソッドは、多次元配列でも使うことが出来ます。 次の例では、Array.CreateInstanceメソッドで指定された型の行列を表す2次元配列を作成し、Array.SetValueメソッドで値を設定して単位行列を構成しています。

Arrayクラスのメソッドを使って多次元配列の作成と要素の値の設定を行う (CreateInstance, GetValue, SetValue))
using System;

class Sample {
  // 任意の長さ・型の単位行列を生成する
  static Array CreateIdentityMatrix(int length, Type typeOfMatrix)
  {
    // 指定された型でlength×length行列となる2次元配列を作成
    var matrix = Array.CreateInstance(typeOfMatrix, length, length);

    // 行列の対角成分に1、それ以外を0に設定する
    for (var i = 0; i < length; i++) {
      for (var j = 0; j < length; j++) {
        if (i == j)
          matrix.SetValue(1, i, j);
        else
          matrix.SetValue(0, i, j);
      }
    }

    return matrix;
  }

  // 行列を表示する
  static void PrintMatrix(Array matrix)
  {
    for (var i = 0; i < matrix.GetLength(1); i++) {
      Console.Write("(");
      for (var j = 0; j < matrix.GetLength(0); j++) {
        Console.Write("{0,-5} ", matrix.GetValue(i, j));
      }
      Console.WriteLine(")");
    }
  }

  static void Main()
  {
    // int型で2行2列の単位行列を作成
    var matrix1 = (int[,])CreateIdentityMatrix(2, typeof(int));

    PrintMatrix(matrix1);
    Console.WriteLine();

    // float型で4行4列の単位行列を作成
    var matrix2 = (float[,])CreateIdentityMatrix(4, typeof(float));

    // 行列内の各要素をスケーリング
    for (var i = 0; i < 4; i++) {
      for (var j = 0; j < 4; j++) {
        matrix2[i, j] *= 0.25f;
      }
    }

    PrintMatrix(matrix2);
    Console.WriteLine();
  }
}
Arrayクラスのメソッドを使って多次元配列の作成と要素の値の設定を行う (CreateInstance, GetValue, SetValue))
Imports System

Class Sample
  ' 任意の長さ・型の単位行列を生成する
  Shared Function CreateIdentityMatrix(ByVal length As Integer, ByVal typeOfMatrix As Type) As Array
    ' 指定された型でlength×length行列となる2次元配列を作成
    Dim matrix As Array = Array.CreateInstance(typeOfMatrix, length, length)

    ' 行列の対角成分に1、それ以外を0に設定する
    For i As Integer = 0 To length - 1
      For j As Integer = 0 To length - 1
        If i = j Then
          matrix.SetValue(1, i, j)
        Else
          matrix.SetValue(0, i, j)
        End If
      Next
    Next

    Return matrix
  End Function

  ' 行列を表示する
  Shared Sub PrintMatrix(ByVal matrix As Array)
    For i As Integer = 0 To matrix.GetLength(1) - 1
      Console.Write("(")
      For j As Integer = 0 To matrix.GetLength(0) - 1
        Console.Write("{0,-5} ", matrix.GetValue(i, j))
      Next
      Console.WriteLine(")")
    Next
  End Sub

  Shared Sub Main()
    ' Integer型で2行2列の単位行列を作成
    Dim matrix1 As Integer(,) = DirectCast(CreateIdentityMatrix(2, GetType(Integer)), Integer(,))

    PrintMatrix(matrix1)
    Console.WriteLine()

    ' Single型で4行4列の単位行列を作成
    Dim matrix2 As Single(,) = DirectCast(CreateIdentityMatrix(4, GetType(Single)), Single(,))

    ' 行列内の各要素をスケーリング
    For i As Integer = 0 To 3
      For j As Integer = 0 To 3
        matrix2(i, j) *= 0.25F
      Next
    Next

    PrintMatrix(matrix2)
    Console.WriteLine()
  End Sub
End Class
実行結果
(1     0     )
(0     1     )

(0.25  0     0     0     )
(0     0.25  0     0     )
(0     0     0.25  0     )
(0     0     0     0.25  )

読み取り専用化 (AsReadOnly)

Array.AsReadOnlyメソッドを使うことで、配列を元に読み取り専用のコレクションを作成することが出来ます。

Array.AsReadOnlyメソッドを使って配列の読み取りビューを作成する
using System;
using System.Collections.ObjectModel;

class Sample {
  static void Main()
  {
    int[] source = {0, 1, 2, 3, 4};

    // 配列を読み取り専用にする
    var arr = Array.AsReadOnly(source);

    // 要素を列挙
    for (var i = 0; i < arr.Count; i++) {
      Console.Write("{0}, ", arr[i]);
    }
    Console.WriteLine();

    // 読み取り専用のため、要素の設定は出来ない
    // sample.cs(20,5): error CS0200: プロパティまたはインデクサー 'System.Collections.ObjectModel.ReadOnlyCollection<int>.this[int]' は読み取り専用なので、割り当てることはできません。
    //arr[1] = 5;

    // IListインターフェイスを経由して、無理やり要素を変更しようとする
    (arr as System.Collections.IList)[0] = 5;
  }
}
Array.AsReadOnlyメソッドを使って配列の読み取りビューを作成する
Imports System
Imports System.Collections.ObjectModel

Class Sample
  Shared Sub Main()
    Dim source() As Integer = {0, 1, 2, 3, 4}

    ' 配列を読み取り専用にする
    Dim arr As ReadOnlyCollection(Of Integer) = Array.AsReadOnly(source)

    ' 要素を列挙
    For i As Integer = 0 To arr.Count - 1
      Console.Write("{0}, ", arr(i))
    Next
    Console.WriteLine()

    ' 読み取り専用のため、要素の設定は出来ない
    ' E:\sample.vb(19) : error BC30526: プロパティ 'Item' は 'ReadOnly' です。
    'arr(1) = 5

    ' IListインターフェイスを経由して、無理やり要素を変更しようとする
    DirectCast(arr, System.Collections.IList)(0) = 5
  End Sub
End Class
実行結果
0, 1, 2, 3, 4,

ハンドルされていない例外: System.NotSupportedException: コレクションは読み取り専用です。
   場所 System.Collections.ObjectModel.ReadOnlyCollection`1.System.Collections.IList.set_Item(Int32 index, Object value)
   場所 Sample.Main()

Array.AsReadOnlyメソッドの戻り値はReadOnlyCollectionで、これは読み取り専用にした配列のように振る舞います。 例えば、インデックスを指定して要素に値を設定しようとするとコンパイルエラーとなり、IList等のインターフェイスにキャストして無理やり変更しようとしてもNotSupportedExceptionがスローされます。

それ以外の操作、例えば要素の参照や値の列挙は、通常の配列と同様に振る舞います。 なお、通常の配列と異なりReadOnlyCollectionにはLengthプロパティが無いので、代わりにCountプロパティを参照します。

ReadOnlyCollectionについてより詳しくは汎用ジェネリックコレクション(1) Collection/ReadOnlyCollection §.ReadOnlyCollectionを参照してください。


Array.AsReadOnlyメソッドは読み取り専用のラッパーを作成するだけであり、元となった配列が読み取り専用となるのではないため、元の配列に対しては依然として値を設定することが可能です。 元の配列を変更すると、作成したReadOnlyCollectionにもその変更が反映されます。

Array.AsReadOnlyメソッドで読み取り専用化した配列のオリジナルに対して変更を加えた場合
using System;
using System.Collections.ObjectModel;

class Sample {
  static void Main()
  {
    int[] source = {0, 1, 2, 3, 4};

    // 配列を読み取り専用にする
    var arr = Array.AsReadOnly(source);

    // 元になった配列に変更を加える
    source[0] = 5;

    // 読み取り専用コレクションの要素を列挙
    for (var i = 0; i < arr.Count; i++) {
      Console.Write("{0}, ", arr[i]);
    }
    Console.WriteLine();
  }
}
Array.AsReadOnlyメソッドで読み取り専用化した配列のオリジナルに対して変更を加えた場合
Imports System
Imports System.Collections.ObjectModel

Class Sample
  Shared Sub Main()
    Dim source() As Integer = {0, 1, 2, 3, 4}

    ' 配列を読み取り専用にする
    Dim arr As ReadOnlyCollection(Of Integer) = Array.AsReadOnly(source)

    ' 元になった配列に変更を加える
    source(0) = 5

    ' 読み取り専用コレクションの要素を列挙
    For i As Integer = 0 To arr.Count - 1
      Console.Write("{0}, ", arr(i))
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
5, 1, 2, 3, 4, 

要素の並べ替え

リバース (Reverse)

Array.Reverseメソッドを使うことで配列内の全要素の並びを逆順に(リバース)することが出来ます。 逆順にする最初のインデックスと要素数を指定することで、配列内の一部分だけを逆順にすることも出来ます。

Array.Reverseメソッドで配列内の要素の並びを逆転する
using System;

class Sample {
  static void Main()
  {
    int[] arr = {0, 1, 2, 3, 4};

    // 配列内の全要素の並びを逆順にする
    Array.Reverse(arr);

    foreach (var elem in arr) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();

    // 配列内のインデックス2から3個分の要素の並びを逆順にする
    Array.Reverse(arr, 2, 3);

    foreach (var elem in arr) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();
  }
}
Array.Reverseメソッドで配列内の要素の並びを逆転する
Imports System

Class Sample
  Shared Sub Main()
    Dim arr() As Integer = {0, 1, 2, 3, 4}

    ' 配列内の全要素の並びを逆順にする
    Array.Reverse(arr)

    For Each elem As Integer In arr
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()

    ' 配列内のインデックス2から3個分の要素の並びを逆順にする
    Array.Reverse(arr, 2, 3)

    For Each elem As Integer In arr
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
4, 3, 2, 1, 0, 
4, 3, 0, 1, 2, 

ジャグ配列をリバースすることも出来ますが、その場合は1段目のみが逆順になります。 2段目以降をリバースする場合は、格納されている配列に対して個別にArray.Reverseメソッドを呼び出してリサイズする必要があります。

なお、Array.Reverseメソッドでは多次元配列を逆順にすることは出来ません。 Array.Reverseメソッドに多次元配列を指定すると、RankExceptionがスローされます。

ソート (Sort)

Array.Sortメソッドを使うことで配列内の全要素をソートして昇順に並べ替えることが出来ます。 ソートする最初のインデックスと要素数を指定することで、配列内の一部分だけをソートすることも出来ます。

Array.Sortメソッドで配列内の要素をソートする
using System;

class Sample {
  static void Main()
  {
    int[] arr1 = {4, 2, 0, 3, 1};

    // 配列内の全要素を昇順に並べ替える
    Array.Sort(arr1);

    foreach (var elem in arr1) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();

    int[] arr2 = {4, 3, 2, 1, 0};

    // 配列内のインデックス2から3個分の要素を昇順に並べ替える
    Array.Sort(arr2, 2, 3);

    foreach (var elem in arr2) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();
  }
}
Array.Sortメソッドで配列内の要素をソートする
Imports System

Class Sample
  Shared Sub Main()
    Dim arr1() As Integer = {4, 2, 0, 3, 1}

    ' 配列内の全要素を昇順に並べ替える
    Array.Sort(arr1)

    For Each elem As Integer In arr1
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()

    Dim arr2() As Integer = {4, 3, 2, 1, 0}

    ' 配列内のインデックス2から3個分の要素を昇順に並べ替える
    Array.Sort(arr2, 2, 3)

    For Each elem As Integer In arr2
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
0, 1, 2, 3, 4, 
4, 3, 0, 1, 2, 

Array.Sortメソッドを使ったソートについてより詳しくは基本型のソートと昇順・降順でのソートで解説しています。 また、Array.Sortメソッドを使って多次元配列やジャグ配列をソートする方法についてはジャグ配列・多次元配列のソートで詳しく解説しています。

シャッフル

Arrayクラスには配列をランダムな順に並べ替える、つまりシャッフルを行うメソッドは用意されていません。 配列をシャッフルするには乱数を使ってソートするなどの方法で独自に実装する必要があります。

配列をシャッフルする具体的な実装例は配列・コレクションのシャッフルで紹介しています。

要素の検索

ここでは配列内にある要素の検索を行うメソッドについて紹介します。 なお、配列の型によっては引数でIComparerなどのインターフェイスが必要になりますが、ここではそういった事項に付いては触れません。 必要に応じて大小関係の定義と比較等価性の定義と比較を参照してください。

要素の位置の検索 (IndexOf, LastIndexOf, BinarySearch)

Array.IndexOfメソッドを使うことで、配列内における指定した値を持つ要素の位置を検索して取得することが出来ます。

このメソッドは配列の前方から検索を行うため、配列内に同一の値を持つ要素がある場合は、そのうちより小さい(最初に見つかった)インデックスを返します。 逆に、Array.LastIndexOfメソッドは配列の後方から検索を行うため、より大きい(前方から見て最後に見つかった)インデックスを返します。 どちらのメソッドも、配列内に該当する要素が無い場合は-1が返されます。

なお、Array.IndexOf, Array.LastIndexOfメソッドでは多次元配列内の要素の位置を検索することは出来ません。 メソッドに多次元配列を指定すると、RankExceptionがスローされます。

Array.IndexOf/LastIndexOfメソッドで要素の位置を前方/後方から検索する
using System;

class Sample {
  static void Main()
  {
    int[] arr = {0, 1, 0, 2, 0, 3};

    // 値に0が格納されている最初のインデックスを取得
    Console.WriteLine("IndexOf(0) = {0}", Array.IndexOf(arr, 0));

    // 値に0が格納されている最後のインデックスを取得
    Console.WriteLine("LastIndexOf(0) = {0}", Array.LastIndexOf(arr, 0));

    // 値に4が格納されている最初のインデックスを取得
    Console.WriteLine("IndexOf(4) = {0}", Array.IndexOf(arr, 4));
  }
}
Array.IndexOf/LastIndexOfメソッドで要素の位置を前方/後方から検索する
Imports System

Class Sample
  Shared Sub Main()
    Dim arr() As Integer = {0, 1, 0, 2, 0, 3}

    ' 値に0が格納されている最初のインデックスを取得
    Console.WriteLine("IndexOf(0) = {0}", Array.IndexOf(arr, 0))

    ' 値に0が格納されている最後のインデックスを取得
    Console.WriteLine("LastIndexOf(0) = {0}", Array.LastIndexOf(arr, 0))

    ' 値に4が格納されている最初のインデックスを取得
    Console.WriteLine("IndexOf(4) = {0}", Array.IndexOf(arr, 4))
  End Sub
End Class
実行結果
IndexOf(0) = 0
LastIndexOf(0) = 4
IndexOf(4) = -1

Array.BinarySearchメソッドを使うことでも配列内における要素の位置を検索出来ます。

Array.IndexOfメソッドは先頭から順に1つずつ要素を検証していくのに対し、Array.BinarySearchメソッドは二分探索によって要素を検索するため、より高速に要素の位置を検索できます(§.IndexOfとBinarySearchの速度比較)。 ただし、いくつかの点でArray.IndexOfメソッドとは異なるため、単純にArray.IndexOfメソッドの代わりとしてArray.BinarySearchメソッドを適用できるとは限りません。

まず、Array.BinarySearchメソッドを使って要素の位置を検索する場合、配列の要素が昇順に並んでいる必要があります。 そのため、Array.BinarySearchメソッドを使う場合は、あらかじめ昇順に並んでいる配列に対して使うか、呼び出す前にあらかじめ配列をソートしておくようにします。 昇順に並んでいない配列に対してArray.BinarySearchメソッドを使った場合でも、例外はスローされず、得られる結果も正しいものにはなりません。

次に、Array.BinarySearchメソッドは該当する要素が見つかった場合はそのインデックスを返しますが、Array.IndexOfメソッドとは異なり、該当する要素が複数ある場合でもそのうちもっとも小さいインデックスが返されるとは限りません。 また、配列内に該当する要素が無い場合は負の数が返されます(-1が返されるとは限りません)。

Array.BinarySearchメソッドを使って二分探索によって要素の位置を検索する
using System;

class Sample {
  static void Main()
  {
    // 要素が昇順に並んでいる配列
    int[] arr = {0, 1, 1, 2, 2, 2, 3, 4, 4, 4, 4, 5};

    // IndexOfメソッドで値に2が格納されているインデックスを取得
    Console.WriteLine("IndexOf(2) = {0}", Array.IndexOf(arr, 2));

    // BinarySearchメソッドで値に2が格納されているインデックスを取得
    Console.WriteLine("BinarySearch(2) = {0}", Array.BinarySearch(arr, 2));

    // 値に7が格納されているインデックスを取得
    Console.WriteLine("IndexOf(7) = {0}", Array.IndexOf(arr, 7));
    Console.WriteLine("BinarySearch(7) = {0}", Array.BinarySearch(arr, 7));
  }
}
Array.BinarySearchメソッドを使って二分探索によって要素の位置を検索する
Imports System

Class Sample
  Shared Sub Main()
    ' 要素が昇順に並んでいる配列
    Dim arr() As Integer = {0, 1, 1, 2, 2, 2, 3, 4, 4, 4, 4, 5}

    ' IndexOfメソッドで値に2が格納されているインデックスを取得
    Console.WriteLine("IndexOf(2) = {0}", Array.IndexOf(arr, 2))

    ' BinarySearchメソッドで値に2が格納されているインデックスを取得
    Console.WriteLine("BinarySearch(2) = {0}", Array.BinarySearch(arr, 2))

    ' 値に7が格納されているインデックスを取得
    Console.WriteLine("IndexOf(7) = {0}", Array.IndexOf(arr, 7))
    Console.WriteLine("BinarySearch(7) = {0}", Array.BinarySearch(arr, 7))
  End Sub
End Class
実行結果
IndexOf(2) = 3
BinarySearch(2) = 5
IndexOf(7) = -1
BinarySearch(7) = -13

なお、Array.BinarySearchメソッドもArray.IndexOfメソッドと同様、多次元配列内の要素の位置を検索することは出来ません。 メソッドに多次元配列を指定すると、RankExceptionがスローされます。

IndexOfとBinarySearchの速度比較

要素数nの配列に対して、IndexOfの速度はO(n)であるのに対し、BinarySearchはO(log2n)となります。

参考までに、Array.IndexOfメソッドとArray.BinarySearchメソッドを使った場合の速度の違いを比較した結果を紹介します。 次のように、IndexOfメソッドを使った検索では配列の要素数が増えるにつれ多大な時間がかかるようになっていますが、BinarySearchメソッドを使った検索では配列の要素数が増えても比較的短い時間で結果が得られています。

要素数が100の場合
Length = 100
IndexOf:      00:00:00.0001335
BinarySearch: 00:00:00.0003081
IndexOf:      00:00:00.0000226
BinarySearch: 00:00:00.0000201
IndexOf:      00:00:00.0000257
BinarySearch: 00:00:00.0000195
要素数が10000の場合
Length = 10000
IndexOf:      00:00:00.1274312
BinarySearch: 00:00:00.0033034
IndexOf:      00:00:00.1212156
BinarySearch: 00:00:00.0018985
IndexOf:      00:00:00.1183027
BinarySearch: 00:00:00.0019239
要素数が100000の場合
Length = 100000
IndexOf:      00:00:12.8952917
BinarySearch: 00:00:00.0278454
IndexOf:      00:00:12.9067753
BinarySearch: 00:00:00.0270422
IndexOf:      00:00:13.0714185
BinarySearch: 00:00:00.0276836
検証に使ったコード
using System;
using System.Diagnostics;

class Sample {
  static void Main()
  {
    // ソート済みの要素を含む配列を作成
    var arr = new int[100 * 1000];

    for (var i = 0; i < arr.Length; i++) {
      arr[i] = i;
    }

    Console.WriteLine("Length = {0}", arr.Length);

    // 3回試行
    for (var c = 0; c < 3; c++) {
      var tick = Environment.TickCount;

      // IndexOfメソッドでの探索
      var rand1 = new Random(tick);
      var sw1 = Stopwatch.StartNew();

      for (var n = 0; n < arr.Length; n++) {
        Array.IndexOf(arr, rand1.Next(0, arr.Length));
      }

      sw1.Stop();

      Console.WriteLine("IndexOf:      {0}", sw1.Elapsed);

      // BinarySearchメソッドでの探索
      var rand2 = new Random(tick);
      var sw2 = Stopwatch.StartNew();

      for (var n = 0; n < arr.Length; n++) {
        Array.BinarySearch(arr, rand2.Next(0, arr.Length));
      }

      sw2.Stop();

      Console.WriteLine("BinarySearch: {0}", sw2.Elapsed);
    }
  }
}

述語を使った検索 (Find, Exists, etc.)

Arrayクラスには、述語(Predicate)を使った要素の検索や取得を行うメソッドがいくつか用意されています。 デリゲートとして条件を記述したものをこれらのメソッドに渡すことによって、その条件に見合う要素を検索・取得することが出来ます。

これらのメソッドを使うことにより、for文・foreach文で列挙してif文で各要素を条件と照らし合わせて検索するといった処理を、メソッドを呼び出すだけで済ませる事が出来るようになります。 言い換えるとfor文・foreach文による配列要素に対する繰り返し処理から、if文等による条件分岐等の処理をメソッド/デリゲートとして分離することができます。

Arrayクラスには、述語を使った要素の検索・取得を行うことが出来るメソッドとして次のようなものが用意されています。

述語を使った要素の検索・取得を行うメソッド
メソッド 機能
Find 述語で定義された条件と一致する最初の要素を取得する
FindLast 述語で定義された条件と一致する最後の要素を取得する
FindAll 述語で定義された条件と一致するすべての要素を取得する
FindIndex 述語で定義された条件と一致する最初の要素のインデックスを取得する
FindLastIndex 述語で定義された条件と一致する最後の要素のインデックスを取得する
Exists 述語で定義された条件と一致する要素があるかどうかを判断する
TrueForAll 述語で定義された条件とすべての要素が合致するかどうかを判断する

次の例では、値が偶数かどうかを返すメソッドを作成し、それを述語として使用することで配列内にある偶数の要素を検索・取得しています。

述語を使って配列内の要素を検索する
using System;

class Sample {
  // 引数で与えられた数が偶数かどうか
  static bool IsEven(int val)
  {
    if (val % 2 == 0)
      return true;
    else
      return false;
  }

  static void Main()
  {
    int[] arr = {1, 4, 3, 5, 2, 6};

    // 「値が偶数かどうか」という述語となるデリゲート
    Predicate<int> isEven = IsEven;

    // 値が偶数の要素とそのインデックスを取得
    Console.WriteLine("Find: {0}", Array.Find(arr, isEven));
    Console.WriteLine("FindIndex: {0}", Array.FindIndex(arr, isEven));
    Console.WriteLine("FindLast: {0}", Array.FindLast(arr, isEven));
    Console.WriteLine("FindLastIndex: {0}", Array.FindLastIndex(arr, isEven));

    // 値が偶数の要素をすべて取得
    Console.Write("FindAll: ");

    foreach (var elem in Array.FindAll(arr, isEven)) {
      Console.Write("{0}, ", elem);
    }

    Console.WriteLine();

    // 値が偶数の要素が存在するかどうか
    Console.WriteLine("Exists? {0}", Array.Exists(arr, isEven));

    // すべての要素の値が偶数かどうか
    Console.WriteLine("TrueForAll? {0}", Array.TrueForAll(arr, isEven));
  }
}
述語を使って配列内の要素を検索する
Imports System

Class Sample
  ' 引数で与えられた数が偶数かどうか
  Shared Function IsNumberEven(ByVal val As Integer) As Boolean
    If val Mod 2 = 0 Then
      Return True
    Else
      Return False
    End If
  End Function

  Shared Sub Main()
    Dim arr() As Integer = {1, 4, 3, 5, 2, 6}

    ' 「値が偶数かどうか」という述語となるデリゲート
    Dim isEven As Predicate(Of Integer) = AddressOf IsNumberEven

    ' 値が偶数の要素とそのインデックスを取得
    Console.WriteLine("Find: {0}", Array.Find(arr, isEven))
    Console.WriteLine("FindIndex: {0}", Array.FindIndex(arr, isEven))
    Console.WriteLine("FindLast: {0}", Array.FindLast(arr, isEven))
    Console.WriteLine("FindLastIndex: {0}", Array.FindLastIndex(arr, isEven))

    ' 値が偶数の要素をすべて取得
    Console.Write("FindAll: ")

    For Each elem As Integer In Array.FindAll(arr, isEven)
      Console.Write("{0}, ", elem)
    Next

    Console.WriteLine()

    ' 値が偶数の要素が存在するかどうか
    Console.WriteLine("Exists? {0}", Array.Exists(arr, isEven))

    ' すべての要素の値が偶数かどうか
    Console.WriteLine("TrueForAll? {0}", Array.TrueForAll(arr, isEven))
  End Sub
End Class
実行結果
Find: 4
FindIndex: 1
FindLast: 6
FindLastIndex: 5
FindAll: 4, 2, 6, 
Exists? True
TrueForAll? False

全要素の変換 (ConvertAll)

Array.ConvertAllメソッドを使うことで、配列内の全要素の値を変換することが出来ます。 このメソッドでは、変換処理を記述したメソッドをConverterデリゲートの形式で指定することで、その処理を配列内の全要素に適用し、その結果を格納した配列を取得することが出来ます。

このメソッドを使うことにより、ある配列を別の型の配列に変換したり、全要素に同じ関数を適用して値を変換する事が出来ます。

Array.ConvertAllメソッドを使って文字列型配列を数値型配列に変換する
using System;

class Sample {
  // 文字列を数値に変換するメソッド
  static int ToInt(string str)
  {
    return int.Parse(str); // 数値として不正な文字列等の処理については省略
  }

  static void Main()
  {
    string[] strings = {"0", "1", "2", "3"};

    // 文字列型配列内のすべての要素を数値に変換する
    var ints = Array.ConvertAll(strings, ToInt);

    foreach (var i in ints) {
      Console.Write("{0}, ", i);
    }
    Console.WriteLine();
  }
}
Array.ConvertAllメソッドを使って文字列型配列を数値型配列に変換する
Imports System

Class Sample
  '  文字列を数値に変換するメソッド
  Shared Function ToInt(ByVal str As String) As Integer
    Return Integer.Parse(str) ' 数値として不正な文字列等の処理については省略
  End Function

  Shared Sub Main()
    Dim strings() As String = {"0", "1", "2", "3"}

    ' 文字列型配列内のすべての要素を数値に変換する
    Dim ints() As Integer = Array.ConvertAll(strings, AddressOf ToInt)

    For Each i As Integer In ints
      Console.Write("{0}, ", i)
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
0, 1, 2, 3, 
Array.ConvertAllメソッドを使って配列内の全ての値を変換する
using System;

class Sample {
  // 度数を弧度に変える
  static double ToRadian(double degree)
  {
    return degree * Math.PI / 180.0;
  }

  static void Main()
  {
    double[] degrees = {0.0, 90.0, 180.0, 270.0};

    // 配列内の値をすべて弧度に変換する
    var radians = Array.ConvertAll(degrees, ToRadian);

    foreach (var rad in radians) {
      Console.Write("{0}, ", rad);
    }
    Console.WriteLine();

    // 配列を文字列の配列に変換して連結する
    Console.WriteLine(string.Join(", ", Array.ConvertAll(degrees, Convert.ToString)));
  }
}
Array.ConvertAllメソッドを使って配列内の全ての値を変換する
Imports System

Class Sample
  ' 度数を弧度に変える
  Shared Function ToRadian(ByVal degree As Double) As Double
    Return degree * Math.PI / 180.0
  End Function

  Shared Sub Main()
    Dim degrees() As Double = {0.0, 90.0, 180.0, 270.0}

    ' 配列内の値をすべて弧度に変換する
    Dim radians() As Double = Array.ConvertAll(degrees, AddressOf ToRadian)

    For Each rad As Double In radians
      Console.Write("{0}, ", rad)
    Next
    Console.WriteLine()

    ' 配列を文字列の配列に変換して連結する
    Console.WriteLine(String.Join(", ", Array.ConvertAll(degrees, AddressOf Convert.ToString)))
  End Sub
End Class
実行結果
0, 1.5707963267949, 3.14159265358979, 4.71238898038469, 
0, 90, 180, 270

要素の列挙 (ForEach)

Array.ForEachメソッドを使うと、配列の要素を列挙してすべての要素に対して同一の処理を施すことが出来ます。 このメソッドでは、処理を記述したメソッドをActionデリゲートの形式で指定することで、配列内の個々の要素を引数としてそのメソッドが呼び出されます。 foreach文の内側でメソッド呼び出しを行う代わりに、このメソッドを使ってより簡単に記述することが出来ます。

Array.ForEachメソッドを使って配列内の全要素を列挙する
using System;

class Sample {
  // 引数の値をゼロ埋めして表示
  static void Print(int val)
  {
    Console.WriteLine("{0:D3}", val);
  }

  static void Main()
  {
    int[] arr = {0, 1, 2, 3, 4};

    // 配列内の値をゼロ埋めして表示
    Array.ForEach(arr, Print);

    Console.WriteLine();

    // 上記の処理をforeach文で記述した場合
    foreach (var elem in arr) {
      Print(elem);
    }
  }
}
Array.ForEachメソッドを使って配列内の全要素を列挙する
Imports System

Class Sample
  ' 引数の値をゼロ埋めして表示
  Shared Sub Print(ByVal val As Integer)
    Console.WriteLine("{0:D3}", val)
  End Sub

  Shared Sub Main()
    Dim arr() As Integer = {0, 1, 2, 3, 4}

    ' 配列内の値をゼロ埋めして表示
    Array.ForEach(arr, AddressOf Print)

    Console.WriteLine()

    ' 上記の処理をFor Eachステートメントで記述した場合
    For Each elem As Integer In arr
      Print(elem)
    Next
  End Sub
End Class
実行結果
000
001
002
003
004

000
001
002
003
004

このメソッドは配列内の各要素を列挙するだけであるため、元の配列に変更を加えるような処理を行うことは出来ません。 そういった処理を行いたい場合はfor文やArray.ConvertAllメソッドを使います。