Visual Basic における配列
配列は、学校の各学年の生徒の数など、互いに論理的に関連する一連の値です。
配列を使うと、これらの関連する値を同じ名前で参照できます。配列の各要素を区別するには、インデックスまたは添字と呼ばれる番号を使います。 個々の値は、配列の要素と呼ばれます。 これは、インデックス 0 から最も大きいインデックス値まで連続しています。
配列とは対照的に、単一の値が含まれている変数はスカラー変数と呼ばれます。
このトピックの内容
単純な配列の配列要素
配列の作成
配列の宣言
配列への値の格納
配列への初期値の取り込み
- 入れ子になった配列リテラル
配列の反復処理
戻り値およびパラメーターとしての配列
ジャグ配列
長さ 0 の配列
配列のサイズ
配列の型および他の型
配列の代わりとしてのコレクション
単純な配列の配列要素
次の例では、学校の各学年の生徒の数を保持するために、配列変数を宣言しています。
Dim students(6) As Integer
上の例の students 配列には、7 つの要素が含まれています。 要素のインデックスの範囲は 0 から 6 までです。 7 つの変数を宣言するよりも、この配列の方がより簡単です。
students 配列を次の図に示します。 配列の各要素は、次のとおりです。
要素のインデックスは、学年を表します (インデックス 0 は幼稚園を表します)。
要素に含まれている値は、その学年の生徒の数を表します。
"生徒" 配列の要素
次の例は、students 配列の先頭の要素、2 番目の要素、および最後の要素を参照する方法を示します。
Dim kindergarten As Integer = students(0)
Dim firstGrade As Integer = students(1)
Dim sixthGrade As Integer = students(6)
MsgBox("Students in kindergarten = " & CStr(kindergarten))
MsgBox("Students in first grade = " & CStr(firstGrade))
MsgBox("Students in sixth grade = " & CStr(sixthGrade))
インデックスを持たない配列変数名だけを使用して、配列全体を参照できます。
前の例の students 配列では、1 つのインデックスが使用されており、これを 1 次元と言います。 複数のインデックスまたは添字が使用されている配列は、多次元と呼ばれます。 詳細については、このトピックの残りの部分と「Visual Basic における配列の次元」を参照してください。
配列の作成
配列のサイズは、さまざまな方法で定義できます。 次の例に示すように、配列を宣言するときにサイズを指定することができます。
Dim cargoWeights(10) As Double
Dim atmospherePressures(2, 2, 4, 10) As Short
Dim inquiriesByYearMonthDay(20)()() As Byte
また、次の例に示すように、New 句を使用して配列を作成するときにサイズを指定することもできます。
cargoWeights = New Double(10) {}
atmospherePressures = New Short(2, 2, 4, 10) {}
inquiriesByYearMonthDay = New Byte(20)()() {}
既存の配列がある場合は、Redim ステートメントを使用してサイズを再定義できます。 Redim ステートメントでは、配列に格納されている値を保持するように指定することも、空の配列を作成するように指定することもできます。 次に、Redim ステートメントを使用して既存の配列のサイズを変更する例をいくつか示します。
' Assign a new array size and retain the current element values.
ReDim Preserve cargoWeights(20)
' Assign a new array size and retain only the first five element values.
ReDim Preserve cargoWeights(4)
' Assign a new array size and discard all current element values.
ReDim cargoWeights(15)
詳細については、「ReDim ステートメント (Visual Basic)」を参照してください。
配列の宣言
配列変数は、他の変数と同じように Dim ステートメントを使用して宣言します。 型または変数名に続けて 1 組以上のかっこを記述することにより、その型または変数がスカラー (1 つの値を含む変数) ではなく配列を保持することを示します。
配列を宣言した後に配列のサイズを定義するには、ReDim ステートメント (Visual Basic) を使用します。
次の例では、型の後に 1 組のかっこを追加して 1 次元配列変数を宣言しています。 さらに、ReDim ステートメント (Visual Basic) を使用して配列の次元を指定しています。
' Declare a one-dimensional array.
Dim cargoWeights As Double()
' Dimension the array.
ReDim cargoWeights(15)
次の例では、多次元配列変数を宣言しています。多次元配列変数を宣言するには、型の後に 1 組のかっこを追加し、かっこの中にコンマを記入して次元を区切ります。 さらに、ReDim ステートメント (Visual Basic) を使用して配列の次元を指定しています。
' Declare a multidimensional array.
Dim atmospherePressures As Short(,,,)
' Dimension the array.
ReDim atmospherePressures(1, 2, 3, 4)
ジャグ配列変数を宣言するには、入れ子になった配列 1 レベルにつき 1 組のかっこを変数名の後に追加します。
Dim inquiriesByYearMonthDay()()() As Byte
上の例では、配列変数を宣言しますが、配列は割り当てられません。 配列を作成して初期化し、変数に割り当てる必要があります。
配列への値の格納
配列のそれぞれの位置には、Integer 型のインデックスを使用してアクセスできます。 かっこで囲まれたインデックスを使用して配列のそれぞれの位置を参照することで、配列の値を格納および取得することができます。 多次元配列のインデックスはコンマ (,) で区切ります。 配列の次元ごとに 1 つのインデックスが必要です。 配列に値を格納するステートメントの例を示します。
Dim i = 4
Dim j = 2
Dim numbers(10) As Integer
Dim matrix(5, 5) As Double
numbers(i + 1) = 0
matrix(3, j * 2) = j
配列から値を取得するステートメントの例を示します。
Dim v = 2
Dim i = 1
Dim j = 1
Dim k = 1
Dim wTotal As Double = 0.0
Dim sortedValues(5), rawValues(5), estimates(2, 2, 2) As Double
Dim lowestValue = sortedValues(0)
wTotal += (rawValues(v) ^ 2)
Dim firstGuess = estimates(i, j, k)
配列への初期値の取り込み
配列リテラルを使用すると、初期値のセットを含む配列を作成できます。 配列リテラルは、中かっこ ({}) で囲んだ値のコンマ区切りの一覧で構成されます。
配列リテラルを使用して配列を作成する場合、配列の型を指定するか、型の推論を使用して配列の型を決定することができます。 この 2 つの方法を次のコードに示します。
Dim numbers = New Integer() {1, 2, 4, 8}
Dim doubles = {1.5, 2, 9.9, 18}
型の推論を使用する場合、配列の型は、配列リテラルに指定された値の一覧の中で最も優先度の高い型によって決まります。 最も優先度の高い型は、配列リテラル内の他のすべての型から拡大変換できる一意の型です。 この一意の型を特定できない場合、最も優先度の高い型は、配列内の他のすべての型から縮小変換できる一意の型になります。 これらの一意の型をどちらも特定できない場合は、Object が最も優先度の高い型になります。 たとえば、配列リテラルに指定された値の一覧に Integer 型、Long 型、および Double 型の値が含まれている場合、結果の配列の型は Double です。 Integer と Long は Double にのみ拡大変換されます。 そのため、Double が最も優先度の高い型になります。 詳細については、「拡大変換と縮小変換 (Visual Basic)」を参照してください。 これらの推論規則は、クラス メンバーで定義されたローカル変数である配列についての型の推論に適用されます。 クラス レベルの変数を作成するときに配列リテラルを使用することはできますが、クラス レベルで型の推論を使用することはできません。 そのため、クラス レベルで指定された配列リテラルでは、配列リテラルに指定された値の型は Object 型であると推論されます。
配列リテラルを使用して作成した配列の要素の型を明示的に指定することができます。 この場合、配列リテラル内の値を配列の要素の型に拡大変換する必要があります。 整数の一覧から Double 型の配列を作成するコード例を次に示します。
Dim values As Double() = {1, 2, 3, 4, 5, 6}
入れ子になった配列リテラル
入れ子になった配列リテラルを使用すると、多次元配列を作成できます。 入れ子になった配列リテラルに含める次元および次元数 (ランク) は、結果の配列と一致する必要があります。 配列リテラルを使用して整数の 2 次元配列を作成するコード例を次に示します。
Dim grid = {{1, 2}, {3, 4}}
上記の例では、入れ子になった配列リテラル内の要素の数が一致しないとエラーが発生します。 また、2 次元以外の配列変数が明示的に宣言された場合もエラーが発生します。
注意
入れ子になった配列リテラルで異なる次元を指定する場合のエラーを回避するには、内側の配列をかっこで囲みます。次のコードに示すように、かっこで囲むことで、配列リテラル式が強制的に評価され、外側の配列リテラルで結果の値が使用されるようになります。
Dim values = {({1, 2}), ({3, 4, 5})}
入れ子になった配列リテラルを使用して多次元配列を作成する場合、型の推論を使用できます。 型の推論を使用すると、推論される型は、入れ子レベルのすべての配列リテラルに含まれるすべての値の中で最も優先度の高い型になります。 Integer 型と Double 型の値から Double 型の 2 次元配列を作成するコード例を次に示します。
Dim a = {{1, 2.0}, {3, 4}, {5, 6}, {7, 8}}
その他の例については、「方法: Visual Basic で配列変数を初期化する」を参照してください。
配列の反復処理
配列を反復処理するときには、配列の各要素に、最もインデックスが小さいものから順番にアクセスします。
次の例では、For...Next ステートメント (Visual Basic) を使用して 1 次元配列を反復処理します。 GetUpperBound メソッドでは、インデックスが保持できる一番高い値が返されます。 一番低いインデックス値は常に 0 です。
Dim numbers = {10, 20, 30}
For index = 0 To numbers.GetUpperBound(0)
Debug.WriteLine(numbers(index))
Next
' Output:
' 10
' 20
' 30
次の例では、For...Next ステートメントを使用して多次元配列を反復処理します。 GetUpperBound メソッドには、次元を指定するパラメーターがあります。 GetUpperBound(0) は最初の次元の最も大きいインデックス値を返し、GetUpperBound(1) は 2 番目の次元の最も大きいインデックス値を返します。
Dim numbers = {{1, 2}, {3, 4}, {5, 6}}
For index0 = 0 To numbers.GetUpperBound(0)
For index1 = 0 To numbers.GetUpperBound(1)
Debug.Write(numbers(index0, index1).ToString & " ")
Next
Debug.WriteLine("")
Next
' Output
' 1 2
' 3 4
' 5 6
次の例では、For Each...Next ステートメント (Visual Basic) を使用して 1 次元配列を反復処理します。
Dim numbers = {10, 20, 30}
For Each number In numbers
Debug.WriteLine(number)
Next
' Output:
' 10
' 20
' 30
次の例では、For Each...Next ステートメントを使用して多次元配列を反復処理します。 ただし、For Each…Next ステートメントを使用するより、前の例のように、入れ子になった For…Next ステートメントを使用した方が、多次元配列の要素をより厳密に制御できます。
Dim numbers = {{1, 2}, {3, 4}, {5, 6}}
For Each number In numbers
Debug.WriteLine(number)
Next
' Output:
' 1
' 2
' 3
' 4
' 5
' 6
戻り値およびパラメーターとしての配列
Function プロシージャから配列を返すには、Function ステートメント (Visual Basic) の戻り値の型として配列のデータ型と次元数を指定します。 関数内で、同じデータ型と次元数を持つローカルの配列変数を宣言して、 かっこを付けずに Return ステートメント (Visual Basic) に含めます。
配列を Sub プロシージャまたは Function プロシージャのパラメーターとして指定するには、パラメーターを配列として定義して、データ型と次元数を指定します。 プロシージャの呼び出しで、データ型と次元数が同じ配列変数を渡します。
次の例では、GetNumbers 関数が Integer() を返します。 この配列型は、Integer 型の 1 次元配列です。 ShowNumbers プロシージャは、Integer() の引数を受け取ります。
Public Sub Process()
Dim numbers As Integer() = GetNumbers()
ShowNumbers(numbers)
End Sub
Private Function GetNumbers() As Integer()
Dim numbers As Integer() = {10, 20, 30}
Return numbers
End Function
Private Sub ShowNumbers(numbers As Integer())
For index = 0 To numbers.GetUpperBound(0)
Debug.WriteLine(numbers(index) & " ")
Next
End Sub
' Output:
' 10
' 20
' 30
次の例では、GetNumbersMultiDim 関数が Integer(,) を返します。 この配列型は、Integer 型の 2 次元配列です。ShowNumbersMultiDim プロシージャは、Integer(,) の引数を受け取ります。
Public Sub ProcessMultidim()
Dim numbers As Integer(,) = GetNumbersMultidim()
ShowNumbersMultidim(numbers)
End Sub
Private Function GetNumbersMultidim() As Integer(,)
Dim numbers As Integer(,) = {{1, 2}, {3, 4}, {5, 6}}
Return numbers
End Function
Private Sub ShowNumbersMultidim(numbers As Integer(,))
For index0 = 0 To numbers.GetUpperBound(0)
For index1 = 0 To numbers.GetUpperBound(1)
Debug.Write(numbers(index0, index1).ToString & " ")
Next
Debug.WriteLine("")
Next
End Sub
' Output
' 1 2
' 3 4
' 5 6
ジャグ配列
他の配列を要素として保持する配列を、配列の配列またはジャグ配列と呼びます。 ジャグ配列と、ジャグ配列の各要素は、1 次元でも多次元でもかまいません。 アプリケーションのデータ構造は、2 次元の配列であっても四角形の 2 次元配列ではない場合があります。
次の例には、各要素が日の配列である月の配列が含まれています。 月によって日数が異なるため、月要素は四角形の 2 次元配列を形成しません。 そのため、多次元配列の代わりにジャグ配列が使用されています。
' Declare the jagged array.
' The New clause sets the array variable to a 12-element
' array. Each element is an array of Double elements.
Dim sales()() As Double = New Double(11)() {}
' Set each element of the sales array to a Double
' array of the appropriate size.
For month As Integer = 0 To 11
Dim days As Integer =
DateTime.DaysInMonth(Year(Now), month + 1)
sales(month) = New Double(days - 1) {}
Next month
' Store values in each element.
For month As Integer = 0 To 11
Dim upper = sales(month).GetUpperBound(0)
For day = 0 To upper
sales(month)(day) = (month * 100) + day
Next
Next
長さ 0 の配列
要素を持たない配列は、長さ 0 の配列と呼ばれます。 長さ 0 の配列を保持する変数の値は、Nothing ではありません。 要素を持たない配列を作成するには、次の例のように配列の次元のいずれかを -1 に宣言します。
Dim twoDimensionalStrings(-1, 3) As String
次のような場合に、長さ 0 の配列を作成する必要があります。
NullReferenceException 例外を発生させずにコードで Array クラスのメンバー (Length、Rank など) にアクセスしたり Visual Basic 関数 (UBound など) を呼び出したりする必要がある場合。
特別なケースですが、Nothing をチェックする必要性をなくすことによって利用側のコードを簡素化する場合。
コードで、長さ 0 の配列を 1 つ以上のプロシージャに渡す必要があるアプリケーション プログラミング インターフェイス (API: Application Programming Interface) とやり取りする場合、または API の 1 つ以上のプロシージャから長さ 0 の配列が返される場合。
配列のサイズ
配列のサイズは、そのすべての次元の長さの積です。 これは、現在配列に含まれている要素の総数を表します。
次の例では 3 次元配列を宣言しています。
Dim prices(3, 4, 5) As Long
変数 prices の配列の全体のサイズは、(3 + 1) x (4 + 1) x (5 + 1) = 120 です。
配列のサイズは、Length プロパティを使用して確認できます。 多次元配列の各次元の長さは、GetLength メソッドを使用して確認できます。
配列変数のサイズを変更するには、新しい配列オブジェクトを割り当てるか、ReDim ステートメントを使用します。
配列のサイズを扱う際に考慮する必要があるいくつかの点があります。
次元の長さ |
各次元のインデックスは 0 ベースであり、範囲は 0 から上限です。 したがって、次元の長さは、その次元に対する宣言された上限よりも 1 だけ大きくなります。 |
長さの制限 |
配列のすべての次元の長さは、(2 ^ 31) - 1 である Integer データ型の最大値に制限されます。 しかし、配列のサイズの総数も、システムで利用できるメモリによって制限されます。 利用できる RAM の容量を超える配列を初期化する場合、共通言語ランタイムは OutOfMemoryException 例外をスローします。 |
サイズおよび要素のサイズ |
配列のサイズは、その要素のデータ型には依存しません。 サイズは常に、使用するストレージのバイト数ではなく、要素の合計数を表します。 |
メモリの使用量 |
配列がメモリに格納される方法に関して、推測で行うのは安全ではありません。 ストレージは、データ幅の異なるプラットフォームによって変わります。したがって、配列が同じであれば、32 ビットのシステムよりも、64 ビットのシステムのほうがより多くのメモリを使用します。 配列を初期化するとき、システム構成に応じて、要素をできるだけ近くに集めるように、またはハードウェア本来の境界条件にすべてをアラインするように、共通言語ランタイム (CLR: Common Language Runtime) によってストレージが割り当てられます。 また、配列は制御情報のためのストレージのオーバーヘッドを必要とします。このオーバーヘッドは、次元が追加されるごとに増加します。 |
配列の型および他の型
すべての配列にデータ型がありますが、要素のデータ型とは異なります。 すべての配列を包括する 1 つのデータ型はありません。 代わりに、配列のデータ型は、配列の次元数 (ランク) と配列の要素のデータ型によって決まります。 ランクと要素のデータ型が一致しない限り、2 つの配列変数が同じデータ型を持つと見なされることはありません。 配列の各次元の長さは、配列のデータ型には影響しません。
すべての配列は、Array クラスから継承しています。また、Array 型として変数を宣言できますが、Array 型の配列は作成できません。 また、ReDim ステートメント (Visual Basic) は、Array 型として宣言された変数上では使用できません。 これらの理由やタイプ セーフにより、すべての配列を、前の例の Integer などの特定の型として宣言することをお勧めします。
いくつかの方法で、配列またはその要素のいずれかのデータ型を知ることができます。
変数の Object.GetType メソッドを呼び出して、実行時型の変数の Type オブジェクトを取得できます。 Type オブジェクトでは、プロパティおよびメソッドに詳細情報が保持されます。
変数を TypeName 関数に渡して、実行時型の名前が含まれる String を取得できます。
変数を VarType 関数に渡して、変数の型の分類を表す VariantType値を受け取ることができます。
TypeName 関数を呼び出して配列の型と配列の要素の型を確認する例を次に示します。 配列の型は Integer(,) で、配列の要素の型は Integer です。
Dim thisTwoDimArray(,) As Integer = New Integer(9, 9) {}
MsgBox("Type of thisTwoDimArray is " & TypeName(thisTwoDimArray))
MsgBox("Type of thisTwoDimArray(0, 0) is " & TypeName(thisTwoDimArray(0, 0)))
配列の代わりとしてのコレクション
配列は、数が固定されている厳密に型指定されたオブジェクトの作成および処理に最も適しています。 コレクションは、オブジェクトのグループをより柔軟に処理できます。 配列の場合とは違って、コレクションで扱うオブジェクトのグループは、アプリケーションのニーズの変化に応じて動的に拡大および縮小できます。
配列のサイズを変更する必要がある場合、ReDim ステートメント (Visual Basic) を使用する必要があります。 これを行うと、Visual Basic により新しい配列が作成され、前の配列が解放されて廃棄されます。 これには、実行時間がかかります。 したがって、操作を行う項目の数が頻繁に変更される場合、または必要な項目の最大数を予測できない場合、コレクションを使用するとパフォーマンスが向上します。
コレクションによっては、コレクションに含まれるオブジェクトのキーを割り当てると、そのキーを使用してオブジェクトを迅速に取り出すことができます。
含まれる要素が 1 つのデータ型だけのコレクションの場合は、System.Collections.Generic 名前空間のクラスのいずれかを使用できます。 ジェネリック コレクションでは、タイプ セーフが強制されるため、他のデータ型を追加することはできません。 ジェネリック コレクションから要素を取得する場合は、データ型を判断したり、変換したりする必要はありません。
コレクションの詳細については、「コレクション (C# および Visual Basic)」を参照してください。
例
.NET Framework のジェネリック クラス List を使用して、Customer オブジェクトの一覧コレクションを作成する例を次に示します。
' Define the class for a customer.
Public Class Customer
Public Property Name As String
' Insert code for other members of customer structure.
End Class
' Create a module-level collection that can hold 200 elements.
Public CustomerList As New List(Of Customer)(200)
' Add a specified customer to the collection.
Private Sub AddNewCustomer(ByVal newCust As Customer)
' Insert code to perform validity check on newCust.
CustomerList.Add(newCust)
End Sub
' Display the list of customers in the Debug window.
Private Sub PrintCustomers()
For Each cust As Customer In CustomerList
Debug.WriteLine(cust)
Next cust
End Sub
CustomerFile コレクションの宣言により、Customer 型だけの要素を含むことができることを指定します。 また、200 要素分の初期容量も用意されています。 AddNewCustomer プロシージャにより、新しい要素の有効性がチェックされ、コレクションに追加されます。 PrintCustomers プロシージャでは、コレクションを走査し、その要素を表示するために、For Each ループが使用されます。
関連トピック
語句 |
定義 |
---|---|
配列のランクと次元について説明します。 |
|
配列に初期値を設定する方法について説明します。 |
|
配列の要素をアルファベット順に並べ替える方法について説明します。 |
|
配列を別の配列変数に代入するときの手順と規則を説明します。 |
|
配列を使用しているときに発生する一般的な問題について説明します。 |