ここではVB.NETでの配列の宣言と操作について見ていきます。

§1 配列の宣言と要素の参照・初期化

配列の宣言と個々の要素を参照する方法はVB6以前からと同じです。 配列(インデックス)のように配列の後ろに丸括弧( )を記述し、その中にインデックス(添え字)を指定することで配列内の個々の要素を参照します。

ただし、VB6以前の配列ではインデックスの下限と上限の両方を指定することができましたが、VB.NETでの配列はCなどと同様にインデックスの下限は0に固定されています。

' インデックスが 0 から 5 まで、要素数 6 の Integer型配列
Dim arr1(5) As Integer

' インデックス0 (配列の先頭の要素) に 2 を代入
arr1(0) = 2

' インデックスが 0 から 9 まで、要素数 10 の String型配列
Dim arr2(9) As String

' インデックス9 (配列の末尾の要素) に "text" を代入
arr2(9) = "text"

配列の宣言時にインデックスを指定しない場合は、配列は作成されず他の配列を代入するための変数となります。 したがって、インデックスを指定した宣言では配列の作成と代入を同時に行なっていると見ることもできます。

' String型配列を代入するための変数 (これだけでは配列は作成されない)
Dim arr1() As String

' 要素数 10 の String型配列
Dim arr2(9) As String

arr1 = arr2

インデックスを指定せずに配列変数を宣言した場合、その変数にはNothingが格納されます。 その状態で配列の要素を参照しようとすると例外NullReferenceExceptionがスローされます。

' String型配列を代入するための変数 (arrにはNothingが代入されている)
Dim arr() As String

arr(0) = "text" ' ここでNullReferenceExceptionがスローされる

また、配列の範囲外を参照しようとした場合には、実行時に例外IndexOutOfRangeExceptionがスローされます。

' インデックスが 0 から 3 まで、要素数 4 の String型配列
Dim arr(3) As String

arr(10) = "text" ' ここでIndexOutOfRangeExceptionがスローされる

配列の宣言と同時に値を格納して初期化するには、次のように中括弧{ }を使って格納する値を指定します。

' 5つの値を格納したInteger型配列
Dim values() As Integer = {3, 1, 4, 5, 2}

Console.WriteLine(values(2)) ' "4"が出力される

' 3つの値を格納したString型配列
Dim names() As String = {"Alice", "Bob", "Charlie"}

Console.WriteLine(names(0)) ' "Alice"が出力される

すでに作成されている配列を初期化(クリア)するにはArray.Clearメソッドを使います。

実行時に配列の要素数(配列の長さ)を調べるには、配列のLengthプロパティを参照します。

' 要素数10のInteger型配列
Dim arr(9) As Integer
Dim len As Integer

len = arr.Length

Console.WriteLine(len) ' "10"が出力される

' 5つの値を格納したInteger型配列
Dim values() As Integer = {3, 1, 4, 5, 2}

Console.WriteLine(values.Length) ' "5"が出力される

' 3つの値を格納したString型配列
Dim names() As String = {"Alice", "Bob", "Charlie"}

Console.WriteLine(names.Length) ' "3"が出力される

配列の宣言時に-1を指定するか、中括弧{ }だけを記述した初期値を指定することで空の配列を作成することができます。 空の配列は格納できる要素数が0であるため、要素を格納することはできません。 空の配列はNullReferenceExceptionが発生するのを避ける目的でNothingを指定する代わりとして使用することがあります。

' 要素数が0の空の配列
Dim arr1(-1) As Integer
Dim arr2() As Integer = {}

その他、配列の宣言と作成や初期値の設定方法については配列の宣言・初期化・基本操作でも詳しく解説しています。

§1.1 多次元配列

多次元配列は次のように宣言します。

' 二次元配列 (要素数は10×10個)
Dim arr1(9, 9) As Integer

' 三次元配列 (要素数は10×10×10個)
Dim arr2(9, 9, 9) As Integer

' 二次元配列を代入するための変数 (これだけでは配列は作成されない)
Dim arr3(,) As Integer

' 三次元配列を代入するための変数 (これだけでは配列は作成されない)
Dim arr4(,,) As Integer

多次元配列において、各次元毎の長さ(サイズ)を取得するにはGetLengthメソッドを使います。 多次元配列ではLengthプロパティは全要素数を返します。

' 3×5の要素数を持つ二次元配列
Dim arr1(2, 4) As Integer

Console.WriteLine(arr1.GetLength(0)) ' 1次元目のサイズを取得する
Console.WriteLine(arr1.GetLength(1)) ' 2次元目のサイズを取得する
Console.WriteLine(arr1.Length) ' 二次元配列の全要素数を取得する
実行結果
3
5
15

Rankプロパティを参照すると、配列の次元数を取得することができます。

' 通常の配列 (一次元配列)
Dim arr1(9) As Integer

' 二次元配列
Dim arr2(2, 4) As Integer

' 三次元配列
Dim arr3(9, 9, 9) As Integer

Console.WriteLine(arr1.Rank) ' "1"が出力される
Console.WriteLine(arr2.Rank) ' "2"が出力される
Console.WriteLine(arr3.Rank) ' "3"が出力される

多少複雑になりますが、多次元配列でも通常の配列と同様に中括弧{ }を使って初期値を指定することができます。 { }が個々の次元を表している点に注目してください。

' 要素数は 2×5 になる
Dim arr1(,) As Integer = {{0, 1, 2, 3, 4}, {5, 6, 7, 8, 9}}

' 要素数は 2×2×5 になる
Dim arr2(,,) As Integer = {{{0, 1, 2, 3, 4}, {5, 6, 7, 8, 9}}, {{10, 11, 12, 13, 14}, {15, 16, 17, 18, 19}}}

次のコードはこれと同じ要素を格納した配列を作成するためのコードです。

' 二次元配列の初期化
Dim arr1(1, 4) As Integer
Dim n As Integer = 0

For i As Integer = 0 To 1
  For j As Integer = 0 To 4
    arr1(i, j) = n
    n += 1
  Next j
Next i
' 三次元配列の初期化
Dim arr2(1, 1, 4) As Integer
Dim n As Integer = 0

For i As Integer = 0 To 1
  For j As Integer = 0 To 1
    For k As Integer = 0 To 4
      arr2(i, j, k) = n
      n += 1
    Next k
  Next j
Next i

多次元配列の他にも、ジャグ配列と呼ばれる配列を宣言することも出来ます。 多次元配列やジャグ配列とその詳細、および初期化などの方法については多次元配列・ジャグ配列で解説しています。



§2 配列と繰り返し構文

繰り返しのステートメントでも解説しているとおり、配列ではForステートメントとFor-Eachステートメントを使って繰り返しを行うことができます。

Dim arr() As String = {"A", "B", "C", "D", "E"}

' Forステートメントですべての要素について繰り返す
For i As Integer = 0 To arr.Length - 1
  Console.Write("{0} ", arr(i))
Next
Console.WriteLine()

' For-Eachステートメントですべての要素について繰り返す
For Each s As String In arr
  Console.Write("{0} ", s)
Next
Console.WriteLine()
実行結果
A B C D E 
A B C D E 

上記の例では配列の先頭から末尾を順に走査して内容を表示しています。 逆に、末尾から先頭への逆順で走査したい場合、Forステートメントでは次の例のようにStep -1を指定することでカウンタ変数をカウントダウンさせるようにします。

Dim arr() As String = {"A", "B", "C", "D", "E"}

' Forステートメントで配列の末尾から先頭の順に表示する
For i As Integer = arr.Length - 1 To 0 Step -1
  Console.Write("{0} ", arr(i))
Next
Console.WriteLine()
実行結果
E D C B A 

For Eachステートメントの場合は、それだけでは逆順に走査することはできません。 Array.Reverseメソッドで配列をあらかじめ逆順に並べ替えてから走査するか、逆順で走査するためのReverse拡張メソッド(LINQ)を使用する必要があります。

Array.Reverseメソッドを使ってFor-Eachで配列を逆順で表示する
Dim arr() As String = {"A", "B", "C", "D", "E"}

' 配列の内容を逆順に並び替える
Array.Reverse(arr)

' 逆順にした配列の内容をFor-Eachステートメントで先頭から順に表示する
For Each s As String In arr
  Console.Write("{0} ", s)
Next
Console.WriteLine()
Reverse拡張メソッドを使ってFor-Eachで配列を逆順で表示する
Imports System.Linq

Dim arr() As String = {"A", "B", "C", "D", "E"}

' 逆順で列挙される配列の内容をFor-Eachステートメントで先頭から順に表示する
For Each s As String In arr.Reverse()
  Console.Write("{0} ", s)
Next
Console.WriteLine()
実行結果
E D C B A 

Array.Reverseメソッドでは配列の内容を変更して逆順にします。 一方Reverse拡張メソッドを使った場合は、元の配列の内容は一切変更されません。

§3 配列の複製・コピー

配列は参照型であるため、次の例のように代入を行なっても、配列自体が複製されるのではなく同一の配列を参照するだけとなります。

Dim arr1(4) As Integer
Dim arr2() As Integer

arr1(0) = 3

' 配列を別の変数に代入
' (複製が行われるわけではなく、単に同一の配列を参照するようになる)
arr2 = arr1

Console.WriteLine(arr1(0)) ' "3"が表示される
Console.WriteLine(arr2(0)) ' arr1(0)と同じ"3"が表示される

' 代入元の配列に変更を加える
arr1(0) = 9

Console.WriteLine(arr1(0)) ' "9"が表示される
Console.WriteLine(arr2(0)) ' arr1(0)と同じ"9"が表示される

配列を複製するにはCloneメソッドを使います。 これにより、内容が全く同じ配列を作成することができます。 このメソッドの戻り値はObjectなので、DirectCastを使って目的の配列型にキャストする必要があります。

Dim arr1(4) As Integer
Dim arr2() As Integer

arr1(0) = 3

' Cloneメソッドで配列を複製する
arr2 = DirectCast(arr1.Clone(), Integer())

Console.WriteLine(arr1(0)) ' "3"が表示される
Console.WriteLine(arr2(0)) ' "3"が表示される

' 複製元の配列に変更を加える
arr1(0) = 9

Console.WriteLine(arr1(0)) ' "9"が表示される
Console.WriteLine(arr2(0)) ' "3"が表示される

配列の一部または全部を別の配列へコピー(複写)するにはArray.Copyメソッドを使います。 Array.Copy(コピー元配列, コピー先配列, コピーする要素数)のように引数を指定します。 コピーされない部分はそのまま維持されます。

Dim arr1() As Integer = {1, 2, 3, 4, 5}
Dim arr2() As Integer = {6, 7, 8, 9, 10}

' arr1の先頭から3個分をarr2にコピー
Array.Copy(arr1, arr2, 3)

' コピーした結果を表示
For Each val As Integer In arr2
  Console.Write("{0}, ", val)
Next
Console.WriteLine()
実行結果
1, 2, 3, 9, 10, 

Array.Copy(コピー元配列, コピー元の最初のインデックス, コピー先配列, コピー先の最初のインデックス, コピーする要素数)のように引数を指定すると、コピー元・コピー先の位置を指定した上でコピーを行うことができます。

Dim arr1() As Integer = {1, 2, 3, 4, 5}
Dim arr2() As Integer = {6, 7, 8, 9, 10}

' arr1(1)からの要素3個をarr2(2)以降にコピー
' (arr1のインデックス1以降の要素を、arr2のインデックス2以降に、要素3個分をコピー)
Array.Copy(arr1, 1, arr2, 2, 3)

' コピーした結果を表示
For Each val As Integer In arr2
  Console.Write("{0}, ", val)
Next
Console.WriteLine()
実行結果
6, 7, 2, 3, 4, 

コピーする要素数がコピー元・コピー先のサイズを超える場合、インデックスがコピー先・コピー元の範囲外となる場合は例外ArgumentExceptionがスローされます。

§4 動的配列・配列のサイズ変更

格納したい要素数が不確定な場合など、動的に配列のサイズを変えることが必要となる場合には、配列よりもListクラスなどの動的配列を実装したクラスを使うことが推奨されます。

ですが、ここではVB.NET固有の機能を紹介する目的で、VB.NETの構文で動的配列を扱う方法について見ていきます。

§4.1 ReDim

ReDimステートメントを使うことにより、配列のサイズを動的に変更することができます。 ReDimステートメントでは配列のサイズを拡張することも縮小することもできます。

' 要素数5のInteger型配列
Dim arr1(4) As Integer

' 配列の要素数を10に変更
ReDim arr1(9)

arr1(9) = 0

' Integer型配列を代入するための変数
Dim arr2() As Integer

' 配列の要素数を10に変更
ReDim arr2(9)

arr2(9) = 0

ReDimだけを用いて配列を宣言することはできません。 つまり、必ず既存の配列を指定するか、先に配列を格納する変数を宣言しておかなければなりません。

多次元配列の場合でも同様にReDimを使用して動的に要素数を変更することができます。

' 二次元配列 (要素数は10×10個)
Dim arr1(9, 9) As Integer

' 三次元配列 (要素数は10×10×10個)
Dim arr2(9, 9, 9) As Integer

' 要素数を20×20個に
ReDim arr1(19, 19)

' 要素数を10×20×30個に
ReDim arr2(9, 19, 29)


' 二次元配列を格納する変数
Dim arr3(,) As Integer

' 三次元配列を格納する変数
Dim arr4(,,) As Integer

' 要素数を10×10個に
ReDim arr3(9, 9)

' 要素数を10×10×10個に
ReDim arr4(9, 9, 9)

ReDimステートメントは、実際には指定された配列のサイズを変更するのではなく、指定されたサイズの配列を新しく作成して配列変数に格納しなおします。 そのため、ReDimの前後では変数に格納されている配列は別々の配列となります。

Dim arr(4) As Integer

' 一時変数に現在の配列を退避する
Dim temp() As Integer = arr

' ReDimで配列のサイズを変更する
ReDim arr(9)

If arr Is temp Then
  Console.WriteLine("arrとtempは同じインスタンスです")
Else
  Console.WriteLine("arrとtempは別のインスタンスです")
End If

Console.WriteLine(arr.Length)
Console.WriteLine(temp.Length)
実行結果
arrとtempは別のインスタンスです
10
5

したがって、次の実行結果からもわかるようにReDimステートメントでは配列のサイズを変更すると内容がすべてクリアされるような結果となります。

Dim arr() As Integer = {1, 2, 3, 4, 5}

' サイズを変更する前の配列の内容を表示する
For i As Integer = 0 To arr.Length - 1
  Console.Write("{0}, ", arr(i))
Next
Console.WriteLine()

' ReDimで配列のサイズを変更する
ReDim arr(9)

' サイズを変更した後の配列の内容を表示する
For i As Integer = 0 To arr.Length - 1
  Console.Write("{0}, ", arr(i))
Next
Console.WriteLine()
実行結果
1, 2, 3, 4, 5, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 

§4.2 ReDim Preserve

ReDimを使って配列のサイズを変更する際に、配列の内容を維持したい場合にはPreserveを付け加えます。

Dim arr() As Integer = {1, 2, 3, 4, 5}

' サイズを変更する前の配列の内容を表示する
For i As Integer = 0 To arr.Length - 1
  Console.Write("{0}, ", arr(i))
Next
Console.WriteLine()

' ReDim Preserveで配列の内容を維持したままサイズを変更する
ReDim Preserve arr(9)

' サイズを変更した後の配列の内容を表示する
For i As Integer = 0 To arr.Length - 1
  Console.Write("{0}, ", arr(i))
Next
Console.WriteLine()
実行結果
1, 2, 3, 4, 5, 
1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 

このほか、Array.Resizeメソッドを使うことでも内容を維持したまま配列のサイズを変更することができます。

多次元配列の場合、ReDim Preserveでは一番最後の次元のサイズのみを変更することができます。 それ以外の次元のサイズを変更しようとした場合には例外ArrayTypeMismatchExceptionがスローされます。

' 二次元配列 (要素数は10×10個)
Dim arr1(9, 9) As Integer

' 2つ目の次元のサイズを変更して要素数を10×20個に
ReDim Preserve arr1(9, 10)

' 1つ目の次元のサイズを変更して要素数を20×20個に
' (実際には例外ArrayTypeMismatchExceptionがスローされる)
ReDim Preserve arr1(19, 19)
' 三次元配列 (要素数は10×10×10個)
Dim arr2(9, 9, 9) As Integer

' 3つ目の次元のサイズを変更して要素数を10×10×20個に
ReDim Preserve arr2(9, 9, 19)

' 1つ目と2つ目の次元のサイズを変更して要素数を20×20×20個に
' (実際には例外ArrayTypeMismatchExceptionがスローされる)
ReDim Preserve arr2(19, 19, 19)

多次元配列の内容を維持したまま各次元のサイズを変更するには、新たなサイズで多次元配列を作成しなおして、要素を一つずつコピーしていく必要があります。

§5 配列のプロパティ・メソッド

VB.NETの配列は、Arrayクラスから派生したオブジェクトとなっています。 そのため、配列はいくつかのプロパティやメソッドを持っています。 ここではその紹介のみを行います。 詳細な解説については配列操作を参照してください。

ここではArrayクラスのメソッドの例として、

を使用しています。

' 一次元配列について
Dim arr() As Integer = {4, 2, 3, 0, 1}

' arrの値を表示
For i As Integer = 0 To arr.Length - 1
  Console.Write("{0} ", arr(i))
Next
Console.WriteLine()

' 並べ替え
Array.Sort(arr)

' arrの値を表示
For i As Integer = 0 To arr.Length - 1
  Console.Write("{0} ", arr(i))
Next
Console.WriteLine()

' 反転
Array.Reverse(arr)

' arrの値を表示
For i As Integer = 0 To arr.Length - 1
  Console.Write("{0} ", arr(i))
Next
Console.WriteLine()

' 1 を含むインデックスを取得する
Dim index As Integer = Array.IndexOf(arr, 1)

Console.WriteLine(index)

' 配列のインデックス0から3要素分クリアする
Array.Clear(arr, 0, 3)

' arrの値を表示
For i As Integer = 0 To arr.Length - 1
  Console.Write("{0} ", arr(i))
Next
Console.WriteLine()
実行結果
4 2 3 0 1
0 1 2 3 4
4 3 2 1 0
3
0 0 0 1 0

このほかにもArrayクラスには様々なメソッドが用意されています。 メソッドによっては多次元配列が扱えないものも存在します。 Arrayクラスのメソッドについてより詳しくは配列操作をご覧ください。