Visual Basic における配列
配列は、論理的に相互に関連する " 要素" と呼ばれる値のセットです。 たとえば、配列は、学校の各学年の生徒の数で構成されている場合があります。この配列の各要素は、1 つの学年の生徒の数です。 同様に、配列はクラスの生徒の成績で構成される場合もあります。この配列の各要素は、1 つの成績です。
個別の変数を使用して各データ項目を格納することができます。 たとえば、アプリケーションで生徒の成績を分析する場合は、englishGrade1
、englishGrade2
など、生徒の成績ごとに個別の変数を使用できます。この方法には主に次の 3 つの制限があります。
- デザイン時に、処理する必要がある成績の数を正確に把握しておく必要がある。
- 成績の数が多いと、迅速に処理するのが難しくなる。 これにより、アプリケーションで深刻なバグが発生する可能性がいっそう高くなります。
- 維持するのが難しい。 新しい成績を追加するたびに、アプリケーションの変更、再コンパイル、再デプロイが必要になります。
配列を使うと、これらの関連する値を同じ名前で参照できます。配列内の位置に基づいて個々の要素を識別するには、"インデックス" または "添字" と呼ばれる番号を使います。 配列のインデックスの範囲は、0 から、配列内の要素の合計数より 1 つ小さい数までとなります。 Visual Basic 構文を使用して配列のサイズを定義する場合は、配列内の要素の合計数ではなく、最も大きいインデックスを指定します。 配列は 1 つの単位として操作できます。また、その要素を反復処理できるため、デザイン時に含まれる要素の数を正確に把握する必要がなくなります。
説明する前に、簡単な例をいくつか紹介します。
' Declare a single-dimension array of 5 numbers.
Dim numbers(4) As Integer
' Declare a single-dimension array and set its 4 values.
Dim numbers = New Integer() {1, 2, 4, 8}
' Change the size of an existing array to 16 elements and retain the current values.
ReDim Preserve numbers(15)
' Redefine the size of an existing array and reset the values.
ReDim numbers(15)
' Declare a 6 x 6 multidimensional array.
Dim matrix(5, 5) As Double
' Declare a 4 x 3 multidimensional array and set array element values.
Dim matrix = New Integer(,) {{1, 2, 3}, {2, 3, 4}, {3, 4, 5}, {4, 5, 6}}
' Declare a jagged array
Dim sales()() As Double = New Double(11)() {}
単純な配列の配列要素
students
という名前の配列を作成し、学校の各学年の生徒の数を格納してみましょう。 要素のインデックスの範囲は 0 から 6 までです。 7 つの変数を宣言するよりも、この配列を使用する方が簡単です。
以下の図には、students
配列が示されています。 配列の各要素は、次のとおりです。
要素のインデックスは、学年を表します (インデックス 0 は幼稚園を表します)。
要素に含まれている値は、その学年の生徒の数を表します。
次の例には、配列を作成して使用する Visual Basic コードが含まれています。
Module SimpleArray
Public Sub Main()
' Declare an array with 7 elements.
Dim students(6) As Integer
' Assign values to each element.
students(0) = 23
students(1) = 19
students(2) = 21
students(3) = 17
students(4) = 19
students(5) = 20
students(6) = 22
' Display the value of each element.
For ctr As Integer = 0 To 6
Dim grade As String = If(ctr = 0, "kindergarten", $"grade {ctr}")
Console.WriteLine($"Students in {grade}: {students(ctr)}")
Next
End Sub
End Module
' The example displays the following output:
' Students in kindergarten: 23
' Students in grade 1: 19
' Students in grade 2: 21
' Students in grade 3: 17
' Students in grade 4: 19
' Students in grade 5: 20
' Students in grade 6: 22
この例では、次の 3 つの処理が行われます。
- 7 つの要素がある
students
配列が宣言されます。 配列宣言内の6
という数値は、配列内の最後のインデックスを示します。これは、配列内の要素の数より 1 つ小さいものです。 - 配列の各要素に値が代入されます。 配列要素にアクセスするには、配列名を使用し、個々の要素のインデックスをかっこで囲んで指定します。
- 配列の各値が一覧表示されます。 この例では、
For
ステートメントを使用し、配列の各要素にインデックス番号でアクセスします。
前の例の students
配列は、1 つのインデックスが使用されているため、1 次元配列となります。 複数のインデックスまたは添字が使用されている配列は、"多次元" と呼ばれます。 詳細については、この記事の残りの部分と、「Visual Basic における配列の次元」を参照してください。
配列の作成
配列のサイズは、次のいくつかの方法で定義できます。
配列が宣言されている場合は、サイズを指定できます。
' Declare an array with 10 elements. Dim cargoWeights(9) As Double ' Declare a 24 x 2 array. Dim hourlyTemperatures(23, 1) As Integer ' Declare a jagged array with 31 elements. Dim januaryInquiries(30)() As String
New
句を使用して、配列の作成時にそのサイズを指定することができます。' Declare an array with 10 elements. Dim cargoWeights() As Double = New Double(9) {} ' Declare a 24 x 2 array. Dim hourlyTemperatures(,) As Integer = New Integer(23, 1) {} ' Declare a jagged array with 31 elements. Dim januaryInquiries()() As String = New String(30)() {}
既存の配列がある場合は、 ReDim
ステートメントを使用してサイズを再定義できます。 ReDim
ステートメントで配列内にある値を保持するように指定することも、空の配列を作成するように指定することもできます。 次に、 ReDim
ステートメントを使用して既存の配列のサイズを変更する例をいくつか示します。
' Assign a new array size and retain the current values.
ReDim Preserve cargoWeights(20)
' Assign a new array size and retain only the first five values.
ReDim Preserve cargoWeights(4)
' Assign a new array size and discard all current element values.
ReDim cargoWeights(15)
詳細については、「ReDim ステートメント」を参照してください。
配列への値の格納
配列のそれぞれの位置には、 Integer
型のインデックスを使用してアクセスできます。 かっこで囲まれたインデックスを使用して配列のそれぞれの位置を参照することで、配列の値を格納および取得することができます。 多次元配列のインデックスはコンマ (,) で区切られます。 配列の次元ごとに 1 つのインデックスが必要です。
次の例では、配列で値を格納および取得するいくつかのステートメントが示されています。
Module Example
Public Sub Main()
' Create a 10-element integer array.
Dim numbers(9) As Integer
Dim value As Integer = 2
' Write values to it.
For ctr As Integer = 0 To 9
numbers(ctr) = value
value *= 2
Next
' Read and sum the array values.
Dim sum As Integer
For ctr As Integer = 0 To 9
sum += numbers(ctr)
Next
Console.WriteLine($"The sum of the values is {sum:N0}")
End Sub
End Module
' The example displays the following output:
' The sum of the values is 2,046
配列への配列リテラルの取り込み
配列リテラルを使用することで、配列を作成するのと同時に値の初期セットをその配列に取り込むことができます。 配列リテラルは、中かっこ ({}
) で囲んだ値のコンマ区切りの一覧で構成されます。
配列リテラルを使用して配列を作成する場合、配列の型を指定するか、型の推定を使用して配列の型を決定することができます。 次の例は、両方のオプションを示しています。
' Array literals with explicit type definition.
Dim numbers = New Integer() {1, 2, 4, 8}
' Array literals with type inference.
Dim doubles = {1.5, 2, 9.9, 18}
' Array literals with explicit type definition.
Dim articles() As String = { "the", "a", "an" }
' Array literals with explicit widening type definition.
Dim values() As Double = { 1, 2, 3, 4, 5 }
型推論を使用する場合、配列の型は、リテラル値の一覧にある "最も優先度の高い型" によって決まります。 最も優先度の高い型は、配列内の他のすべての型から拡大変換できる型です。 この一意の型を特定できない場合、最も優先度の高い型は、配列内の他のすべての型から縮小変換できる一意の型になります。 これらの一意の型をどちらも特定できない場合は、 Object
が最も優先度の高い型になります。 たとえば、配列リテラルに指定された値の一覧に Integer
型、 Long
型、および Double
型の値が含まれている場合、結果の配列の型は Double
です。 Integer
と Long
は Double
にのみ拡大変換されるため、Double
が最も優先度の高い型となります。 詳細については、「 Widening and Narrowing Conversions」を参照してください。
Note
型推論は、型のメンバーでローカル変数として定義されている配列に対してのみ使用できます。 明示的な型定義が存在しない場合、クラス レベルで配列リテラルを使用して定義された配列の型は Object[]
となります。 詳細については、「ローカル型の推論」を参照してください。
前の例では、すべての配列リテラルが Integer
型であっても、Double
型の配列として values
が定義されていることに注意してください。 配列リテラルの値を Double
値に拡大変換できるため、この配列を作成することができます。
また、"入れ子になった配列リテラル" を使用して、多次元配列を作成および設定することもできます。 入れ子になった配列リテラルには、結果の配列と一致する次元数が必要です。 次の例では、入れ子になった配列リテラルを使用して、整数の 2 次元配列を作成します。
' Create and populate a 2 x 2 array.
Dim grid1 = {{1, 2}, {3, 4}}
' Create and populate a 2 x 2 array with 3 elements.
Dim grid2(,) = {{1, 2}, {3, 4}, {5, 6}}
入れ子になった配列リテラルを使用して配列を作成および設定する場合、その入れ子になった配列リテラル内の要素の数が一致しないと、エラーが発生します。 配列リテラルとは次元数が異なる配列変数を明示的に宣言した場合にも、エラーが発生します。
1 次元配列の場合と同じように、入れ子になった配列リテラルを使用して多次元配列を作成する場合は、型推論を利用できます。 推論型は、すべての入れ子レベルのすべての配列リテラルに含まれるすべての値の中で最も優先度の高い型になります。 次の例では、Integer
および Double
型の値から Double[,]
型の 2 次元配列を作成します。
Dim arr = {{1, 2.0}, {3, 4}, {5, 6}, {7, 8}}
その他の例については、「方法: Visual Basic で配列変数を初期化する」を参照してください。
配列の反復処理
配列を反復処理する場合、配列の各要素には、インデックスが最も小さいものから、あるいは最も大きいものから順にアクセスします。 通常は、For...Next ステートメントまたは For Each...Next ステートメントを使用して、配列の要素を反復処理します。 配列の上限がわからない場合は、Array.GetUpperBound メソッドを呼び出して、インデックスの最大値を取得できます。 ほとんどの場合、最も小さいインデックス値は 0 ですが、Array.GetLowerBound メソッドを呼び出して、インデックスの最小値を取得できます。
次の例では、For...Next
ステートメントを使用して、1 次元配列を反復処理します。
Module IterateArray
Public Sub Main()
Dim numbers = {10, 20, 30}
For index = 0 To numbers.GetUpperBound(0)
Console.WriteLine(numbers(index))
Next
End Sub
End Module
' The example displays the following output:
' 10
' 20
' 30
次の例では、 For...Next
ステートメントを使用して多次元配列を反復処理します。 GetUpperBound メソッドには、次元を指定するパラメーターがあります。 GetUpperBound(0)
では最初の次元の最も大きいインデックスが返され、GetUpperBound(1)
では 2 番目の次元の最も大きいインデックスが返されます。
Module IterateArray
Public Sub Main()
Dim numbers = {{1, 2}, {3, 4}, {5, 6}}
For index0 = 0 To numbers.GetUpperBound(0)
For index1 = 0 To numbers.GetUpperBound(1)
Console.Write($"{numbers(index0, index1)} ")
Next
Console.WriteLine()
Next
End Sub
End Module
' The example displays the following output:
' Output
' 1 2
' 3 4
' 5 6
次の例では、For Each...Next ステートメントを使用して、1 次元配列と 2 次元配列を反復処理します。
Module IterateWithForEach
Public Sub Main()
' Declare and iterate through a one-dimensional array.
Dim numbers1 = {10, 20, 30}
For Each number In numbers1
Console.WriteLine(number)
Next
Console.WriteLine()
Dim numbers = {{1, 2}, {3, 4}, {5, 6}}
For Each number In numbers
Console.WriteLine(number)
Next
End Sub
End Module
' The example displays the following output:
' 10
' 20
' 30
'
' 1
' 2
' 3
' 4
' 5
' 6
配列のサイズ
配列のサイズは、そのすべての次元の長さの積です。 これは、現在配列に含まれている要素の総数を表します。 たとえば、次の例では、各次元に 4 つの要素がある 2 次元配列を宣言しています。 この例からの出力に示されているように、配列のサイズは 16 (つまり、(3 + 1) * (3 + 1)) です。
Module Example
Public Sub Main()
Dim arr(3, 3) As Integer
Console.WriteLine(arr.Length)
End Sub
End Module
' The example displays the following output:
' 16
Note
配列のサイズに関するこの説明は、ジャグ配列には適用されません。 ジャグ配列とジャグ配列のサイズの確認については、「ジャグ配列」セクションを参照してください。
配列のサイズは、Array.Length プロパティを使用して確認できます。 多次元配列の各次元の長さは、Array.GetLength メソッドを使用して確認できます。
配列変数のサイズ変更は、新しい配列オブジェクトを代入するか、ReDim
ステートメントを使用して行うことができます。 次の例では、ReDim
ステートメントを使用して、100 要素の配列を 51 要素の配列に変更します。
Module Example
Public Sub Main()
Dim arr(99) As Integer
Console.WriteLine(arr.Length)
Redim arr(50)
Console.WriteLine(arr.Length)
End Sub
End Module
' The example displays the following output:
' 100
' 51
配列のサイズを扱う際に考慮する必要がある点がいくつかあります。
メモ | |
---|---|
次元の長さ | 各次元のインデックスは 0 ベースです。これは、範囲が 0 からその上限までであることを意味します。 したがって、指定された次元の長さは、その次元の宣言された上限よりも 1 つ大きくなります。 |
長さの制限 | 配列のすべての次元の長さは、Integer データ型の最大値 (Int32.MaxValue、つまり、(2 ^ 31) - 1) に制限されます。 しかし、配列のサイズの総数も、システムで利用できるメモリによって制限されます。 利用できるメモリの容量を超える配列を初期化しようとすると、ランタイムで OutOfMemoryException がスローされます。 |
サイズおよび要素のサイズ | 配列のサイズは、その要素のデータ型には依存しません。 サイズは常に、メモリで使用されるバイト数ではなく、要素の合計数を表します。 |
メモリの使用量 | 配列がどのようにメモリに格納されるかに関して、前提を置くことは安全ではありません。 ストレージは、プラットフォームのデータ幅が異なると変わります。したがって、同じ配列でも、32 ビットのシステムよりも 64 ビットのシステムの方が多くのメモリを使用します。 配列を初期化すると、システム構成に応じて、要素をできるだけ近くに集めるように、またはすべてがハードウェア自体の境界に合致するように、共通言語ランタイム (CLR: Common Language Runtime) によってストレージが割り当てられます。 また、配列は制御情報のためにストレージのオーバーヘッドを必要とします。このオーバーヘッドは、次元が追加されるごとに増加します。 |
配列型
すべての配列にデータ型があります。これは、その要素のデータ型とは異なります。 すべての配列を包括する 1 つのデータ型はありません。 代わりに、配列のデータ型は、配列の次元数 ( ランク) と配列の要素のデータ型によって決まります。 2 つの配列変数のデータ型が同じになるのは、ランクが同じで、その要素のデータ型が同じである場合のみです。 配列の各次元の長さは、配列のデータ型には影響しません。
すべての配列は、System.Array クラスから継承しています。また、Array
型として変数を宣言できますが、Array
型の配列は作成できません。 たとえば、次のコードでは、arr
変数を Array
型として宣言し、Array.CreateInstance メソッドを呼び出して配列をインスタンス化していますが、配列の型は Object[] であることがわかっています。
Module Example
Public Sub Main()
Dim arr As Array = Array.CreateInstance(GetType(Object), 19)
Console.WriteLine(arr.Length)
Console.WriteLine(arr.GetType().Name)
End Sub
End Module
' The example displays the following output:
' 19
' Object[]
また、ReDim ステートメント は、Array
型として宣言された変数上では使用できません。 これらの理由やタイプ セーフを考慮して、すべての配列を特定の型として宣言することをお勧めします。
いくつかの方法で、配列またはその要素のいずれかのデータ型を知ることができます。
- 変数で GetType メソッドを呼び出して、実行時型の変数を表す Type オブジェクトを取得できます。 Type オブジェクトでは、プロパティおよびメソッドに詳細情報が保持されます。
- 変数を TypeName 関数に渡して、実行時型の名前を含む
String
を取得できます。
次の例では、GetType
メソッドと TypeName
関数の両方を呼び出して、配列の型を確認します。 配列の型は Byte(,)
です。 Type.BaseType プロパティは、バイト配列の基本型が Array クラスであることも示していることに注意してください。
Module Example
Public Sub Main()
Dim bytes(9,9) As Byte
Console.WriteLine($"Type of {nameof(bytes)} array: {bytes.GetType().Name}")
Console.WriteLine($"Base class of {nameof(bytes)}: {bytes.GetType().BaseType.Name}")
Console.WriteLine()
Console.WriteLine($"Type of {nameof(bytes)} array: {TypeName(bytes)}")
End Sub
End Module
' The example displays the following output:
' Type of bytes array: Byte[,]
' Base class of bytes: Array
'
' Type of bytes array: Byte(,)
戻り値およびパラメーターとしての配列
Function
プロシージャから配列を返すには、Function ステートメントの戻り値の型として配列のデータ型と次元数を指定します。 関数内で、同じデータ型と次元数を持つローカルの配列変数を宣言します。 Return ステートメントには、かっこを使用せずにローカルの配列変数を含めます。
配列を Sub
プロシージャまたは Function
プロシージャのパラメーターとして指定するには、パラメーターを配列として定義して、データ型と次元数を指定します。 プロシージャの呼び出しで、データ型と次元数が同じ配列変数を渡します。
次の例では、GetNumbers
関数で Integer()
(Integer
型の 1 次元配列) が返されます。 ShowNumbers
プロシージャは、 Integer()
の引数を受け取ります。
Module ReturnValuesAndParams
Public Sub Main()
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)
Console.WriteLine($"{numbers(index)} ")
Next
End Sub
End Module
' The example displays the following output:
' 10
' 20
' 30
次の例では、GetNumbersMultiDim
関数で Integer(,)
(Integer
型の 2 次元配列) が返されます。 ShowNumbersMultiDim
プロシージャは、 Integer(,)
の引数を受け取ります。
Module Example
Public Sub Main()
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)
Console.Write($"{numbers(index0, index1)} ")
Next
Console.WriteLine()
Next
End Sub
End Module
' The example displays the following output:
' 1 2
' 3 4
' 5 6
ジャグ配列
アプリケーションのデータ構造は、2 次元の配列であっても四角形の 2 次元配列ではない場合があります。 たとえば、配列を使用して、月の各日の高い気温に関するデータを格納することができます。 配列の最初の次元は月を表しますが、2 番目の次元は日数を表し、月の日数は一様ではありません。 "ジャグ配列" ("配列の配列" ともいう) は、このようなシナリオ向けに設計されています。 ジャグ配列は、その要素も配列である配列です。 ジャグ配列と、ジャグ配列の各要素は、1 次元でも多次元でもかまいません。
次の例では、各要素が日の配列である、月の配列を使用しています。 この例では、月によって日数が異なるため、ジャグ配列を使用しています。 この例では、ジャグ配列を作成し、値を代入し、その値を取得して表示する方法が示されています。
Imports System.Globalization
Module JaggedArray
Public Sub Main()
' Declare the jagged array of 12 elements. Each element is an array of Double.
Dim sales(11)() As Double
' Set each element of the sales array to a Double array of the appropriate size.
For month As Integer = 0 To 11
' The number of days in the month determines the appropriate size.
Dim daysInMonth As Integer =
DateTime.DaysInMonth(Year(Now), month + 1)
sales(month) = New Double(daysInMonth - 1) {}
Next
' Store values in each element.
For month As Integer = 0 To 11
For dayOfMonth = 0 To sales(month).GetUpperBound(0)
sales(month)(dayOfMonth) = (month * 100) + dayOfMonth
Next
Next
' Retrieve and display the array values.
Dim monthNames = DateTimeFormatInfo.CurrentInfo.AbbreviatedMonthNames
' Display the month names.
Console.Write(" ")
For ctr = 0 To sales.GetUpperBound(0)
Console.Write($" {monthNames(ctr)} ")
Next
Console.WriteLine()
' Display data for each day in each month.
For dayInMonth = 0 To 30
Console.Write($"{dayInMonth + 1,2}. ")
For monthNumber = 0 To sales.GetUpperBound(0)
If dayInMonth > sales(monthNumber).GetUpperBound(0) Then
Console.Write(" ")
Else
Console.Write($"{sales(monthNumber)(dayInMonth),-5} ")
End If
Next
Console.WriteLine()
Next
End Sub
End Module
' The example displays the following output:
' Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
' 1. 0 100 200 300 400 500 600 700 800 900 1000 1100
' 2. 1 101 201 301 401 501 601 701 801 901 1001 1101
' 3. 2 102 202 302 402 502 602 702 802 902 1002 1102
' 4. 3 103 203 303 403 503 603 703 803 903 1003 1103
' 5. 4 104 204 304 404 504 604 704 804 904 1004 1104
' 6. 5 105 205 305 405 505 605 705 805 905 1005 1105
' 7. 6 106 206 306 406 506 606 706 806 906 1006 1106
' 8. 7 107 207 307 407 507 607 707 807 907 1007 1107
' 9. 8 108 208 308 408 508 608 708 808 908 1008 1108
' 10. 9 109 209 309 409 509 609 709 809 909 1009 1109
' 11. 10 110 210 310 410 510 610 710 810 910 1010 1110
' 12. 11 111 211 311 411 511 611 711 811 911 1011 1111
' 13. 12 112 212 312 412 512 612 712 812 912 1012 1112
' 14. 13 113 213 313 413 513 613 713 813 913 1013 1113
' 15. 14 114 214 314 414 514 614 714 814 914 1014 1114
' 16. 15 115 215 315 415 515 615 715 815 915 1015 1115
' 17. 16 116 216 316 416 516 616 716 816 916 1016 1116
' 18. 17 117 217 317 417 517 617 717 817 917 1017 1117
' 19. 18 118 218 318 418 518 618 718 818 918 1018 1118
' 20. 19 119 219 319 419 519 619 719 819 919 1019 1119
' 21. 20 120 220 320 420 520 620 720 820 920 1020 1120
' 22. 21 121 221 321 421 521 621 721 821 921 1021 1121
' 23. 22 122 222 322 422 522 622 722 822 922 1022 1122
' 24. 23 123 223 323 423 523 623 723 823 923 1023 1123
' 25. 24 124 224 324 424 524 624 724 824 924 1024 1124
' 26. 25 125 225 325 425 525 625 725 825 925 1025 1125
' 27. 26 126 226 326 426 526 626 726 826 926 1026 1126
' 28. 27 127 227 327 427 527 627 727 827 927 1027 1127
' 29. 28 228 328 428 528 628 728 828 928 1028 1128
' 30. 29 229 329 429 529 629 729 829 929 1029 1129
' 31. 30 230 430 630 730 930 1130
前の例では、For...Next
ループを使用して、要素ごとにジャグ配列に値を代入しています。 入れ子になった配列リテラルを使用して、ジャグ配列の要素に値を代入することもできます。 しかし、入れ子になった配列リテラル (Dim valuesjagged = {{1, 2}, {2, 3, 4}}
など) を使用しようとすると、コンパイラ エラー BC30568 が生成されます。 このエラーを解決するには、内側の配列リテラルをかっこで囲みます。 次の例に示すように、かっこで囲むと、配列リテラル式が強制的に評価され、その結果の値が外側の配列リテラルで使用されます。
Module Example
Public Sub Main()
Dim values1d = { 1, 2, 3 }
Dim values2d = {{1, 2}, {2, 3}, {3, 4}}
Dim valuesjagged = {({1, 2}), ({2, 3, 4})}
End Sub
End Module
ジャグ配列は、要素に配列が含まれる 1 次元配列です。 したがって、Array.Length プロパティと Array.GetLength(0)
メソッドでは、1 次元配列内の要素の数が返され、Array.GetLength(1)
では IndexOutOfRangeException がスローされます。これは、ジャグ配列が多次元ではないためです。 各サブ配列内の要素の数は、各サブ配列の Array.Length プロパティの値を取得して確認します。 次の例には、ジャグ配列内の要素の数を確認する方法が示されています。
Module Example
Public Sub Main()
Dim jagged = { ({1, 2}), ({2, 3, 4}), ({5, 6}), ({7, 8, 9, 10}) }
Console.WriteLine($"The value of jagged.Length: {jagged.Length}.")
Dim total = jagged.Length
For ctr As Integer = 0 To jagged.GetUpperBound(0)
Console.WriteLine($"Element {ctr + 1} has {jagged(ctr).Length} elements.")
total += jagged(ctr).Length
Next
Console.WriteLine($"The total number of elements in the jagged array: {total}")
End Sub
End Module
' The example displays the following output:
' The value of jagged.Length: 4.
' Element 1 has 2 elements.
' Element 2 has 3 elements.
' Element 3 has 2 elements.
' Element 4 has 4 elements.
' The total number of elements in the jagged array: 15
長さ 0 の配列
Visual Basic では、初期化されていない配列 (値が Nothing
である配列) と "長さ 0 の配列" または空の配列 (要素がない配列) が区別されます。初期化されていない配列は、次元が指定されていないか、任意の値が代入されているものです。 次に例を示します。
Dim arr() As String
長さ 0 の配列は、次元 -1 で宣言されています。 次に例を示します。
Dim arrZ(-1) As String
次のような場合に、長さ 0 の配列を作成する必要があります。
NullReferenceException 例外を発生させずに、コードで Array クラスのメンバー (Length や Rank など) にアクセスするか、Visual Basic 関数 (UBound など) を呼び出す必要がある場合。
特別なケースとして、
Nothing
をチェックする必要性をなくすことによって、コードを単純なものにしておく場合。コードで、長さ 0 の配列を 1 つ以上のプロシージャに渡す必要があるアプリケーション プログラミング インターフェイス (API: Application Programming Interface) とやり取りする場合、または API の 1 つ以上のプロシージャから長さ 0 の配列が返される場合。
配列の分割
場合によっては、1 つの配列を複数の配列に分割する必要があります。 その場合、配列が分割されるポイントを特定し、その配列を 2 つ以上の個別の配列に分割します。
Note
このセクションでは、区切り記号に基づいて 1 つの文字列を文字列配列に分割する方法については説明しません。 文字列の分割については、String.Split メソッドを参照してください。
配列を分割する場合の最も一般的な条件は次のとおりです。
配列の要素数。 たとえば、指定された数を超える要素の配列を、ほぼ同数の部分に分割することができます。 このために、Array.Length または Array.GetLength メソッドで返された値を使用できます。
要素の値。これは、配列を分割する場所を示す区切り記号として機能します。 Array.FindIndex および Array.FindLastIndex メソッドを呼び出すことで、特定の値を検索できます。
配列を分割する必要があるインデックスを確認したら、Array.Copy メソッドを呼び出して、個々の配列を作成できます。
次の例では、配列を、サイズがほぼ等しい 2 つの配列に分割します (配列要素の合計数が奇数の場合、最初の配列の要素は、2 番目の配列よりも 1 つ多くなります)。
Module Example
Public Sub Main()
' Create an array of 100 elements.
Dim arr(99) As Integer
' Populate the array.
Dim rnd As new Random()
For ctr = 0 To arr.GetUpperBound(0)
arr(ctr) = rnd.Next()
Next
' Determine how many elements should be in each array.
Dim divisor = 2
Dim remainder As Integer
Dim boundary = Math.DivRem(arr.GetLength(0), divisor, remainder)
' Copy the array.
Dim arr1(boundary - 1 + remainder), arr2(boundary - 1) as Integer
Array.Copy(arr, 0, arr1, 0, boundary + remainder)
Array.Copy(arr, boundary + remainder, arr2, 0, arr.Length - boundary)
End Sub
End Module
次の例では、配列の区切り記号として機能する、値が "zzz" である要素の有無に基づいて、文字列の配列を 2 つの配列に分割します。 新しい配列には、区切り記号を含む要素は含まれません。
Module Example
Public Sub Main()
Dim rnd As New Random()
' Create an array of 100 elements.
Dim arr(99) As String
' Populate each element with an arbitrary ASCII character.
For ctr = 0 To arr.GetUpperBound(0)
arr(ctr) = ChrW(Rnd.Next(&h21, &h7F))
Next
' Get a random number that will represent the point to insert the delimiter.
arr(rnd.Next(0, arr.GetUpperBound(0))) = "zzz"
' Find the delimiter.
Dim location = Array.FindIndex(arr, Function(x) x = "zzz")
' Create the arrays.
Dim arr1(location - 1) As String
Dim arr2(arr.GetUpperBound(0) - location - 1) As String
' Populate the two arrays.
Array.Copy(arr, 0, arr1, 0, location)
Array.Copy(arr, location + 1, arr2, 0, arr.GetUpperBound(0) - location)
End Sub
End Module
配列の結合
多数の配列を、1 つのより大きな配列にまとめることもできます。 これを行う場合、Array.Copy メソッドも使用します。
Note
このセクションでは、文字列配列を 1 つの文字列に結合する方法については説明しません。 文字列配列の結合については、String.Join メソッドを参照してください。
各配列の要素を新しい配列にコピーする前に、まず、その新しい配列を格納するのに十分な大きさになるように、配列を確実に初期化しておく必要があります。 2 つの方法のいずれかでこれを行うことができます。
ReDim Preserve
ステートメントを使用し、新しい要素を追加する前に配列を動的に拡張します。 これは最も簡単な方法ですが、大きな配列をコピーする場合は、パフォーマンスが低下し、メモリの消費が過剰になる可能性があります。- 新しい大きな配列に必要な要素の合計数を計算してから、各ソース配列の要素を追加します。
次の例では、2 番目の方法を使用して、それぞれ 10 個の要素がある 4 つの配列を 1 つの配列に追加します。
Imports System.Collections.Generic
Imports System.Threading.Tasks
Module Example
Public Sub Main()
Dim tasks As New List(Of Task(Of Integer()))
' Generate four arrays.
For ctr = 0 To 3
Dim value = ctr
tasks.Add(Task.Run(Function()
Dim arr(9) As Integer
For ndx = 0 To arr.GetUpperBound(0)
arr(ndx) = value
Next
Return arr
End Function))
Next
Task.WaitAll(tasks.ToArray())
' Compute the number of elements in all arrays.
Dim elements = 0
For Each task In tasks
elements += task.Result.Length
Next
Dim newArray(elements - 1) As Integer
Dim index = 0
For Each task In tasks
Dim n = task.Result.Length
Array.Copy(task.Result, 0, newArray, index, n)
index += n
Next
Console.WriteLine($"The new array has {newArray.Length} elements.")
End Sub
End Module
' The example displays the following output:
' The new array has 40 elements.
この場合、ソース配列はすべて小さいため、新しい各配列の要素を追加するときに、配列を動的に拡張することもできます。 次の例でこれを確認できます。
Imports System.Collections.Generic
Imports System.Threading.Tasks
Module Example
Public Sub Main()
Dim tasks As New List(Of Task(Of Integer()))
' Generate four arrays.
For ctr = 0 To 3
Dim value = ctr
tasks.Add(Task.Run(Function()
Dim arr(9) As Integer
For ndx = 0 To arr.GetUpperBound(0)
arr(ndx) = value
Next
Return arr
End Function))
Next
Task.WaitAll(tasks.ToArray())
' Dimension the target array and copy each element of each source array to it.
Dim newArray() As Integer = {}
' Define the next position to copy to in newArray.
Dim index = 0
For Each task In tasks
Dim n = Task.Result.Length
ReDim Preserve newArray(newArray.GetUpperBound(0) + n)
Array.Copy(task.Result, 0, newArray, index, n)
index += n
Next
Console.WriteLine($"The new array has {newArray.Length} elements.")
End Sub
End Module
' The example displays the following output:
' The new array has 40 elements.
配列の代わりとしてのコレクション
配列は、数が固定されている厳密に型指定されたオブジェクトの作成および処理に最も適しています。 コレクションは、オブジェクトのグループをより柔軟に処理できます。 配列のサイズを ReDim
ステートメント で明示的に変更する必要がある配列とは異なり、コレクションは、アプリケーションの変更のニーズに合わせて動的に拡大および縮小します。
ReDim
を使用して配列の次元を変更すると、Visual Basic で新しい配列が作成され、前のものが解放されます。 これには、実行時間がかかります。 したがって、操作を行う項目の数が頻繁に変更される場合、または必要な項目の最大数を予測できない場合は、通常、コレクションを使用することでパフォーマンスが向上します。
コレクションによっては、コレクションに含まれるオブジェクトのキーを割り当てると、そのキーを使用してオブジェクトを迅速に取り出すことができます。
含まれる要素が 1 つのデータ型だけのコレクションの場合は、 System.Collections.Generic 名前空間のクラスのいずれかを使用できます。 ジェネリック コレクションでは、タイプ セーフが強制されるため、他のデータ型を追加することはできません。
コレクションの詳細については、「コレクション」を参照してください。
関連トピック
用語 | 定義 |
---|---|
Array Dimensions in Visual Basic | 配列のランクと次元について説明します。 |
方法: Visual Basic で配列変数を初期化する | 配列に初期値を設定する方法について説明します。 |
方法: Visual Basic で配列を並べ替える | 配列の要素をアルファベット順に並べ替える方法について説明します。 |
方法: 配列を別の配列に代入する | 配列を別の配列変数に代入するときの手順と規則を説明します。 |
配列のトラブルシューティング | 配列を使用しているときに発生する一般的な問題について説明します。 |