次の方法で共有


Visual Basic の配列

配列は、論理的に相互に関連する一連の値 ( 要素と呼ばれる) です。 たとえば、配列は、文法学校の各学年の学生の数で構成される場合があります。配列の各要素は、1 つの成績の学生の数です。 同様に、配列はクラスの学生の成績で構成される場合があります。配列の各要素は 1 つのグレードです。

個々の変数を使用して、各データ項目を格納することができます。 たとえば、アプリケーションで学生の成績を分析する場合、 englishGrade1englishGrade2など、学生の成績ごとに個別の変数を使用できます。この方法には、次の 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型になります。 IntegerLongDoubleにのみ拡大されるため、Doubleが優先型です。 詳細については、「 拡大/縮小変換」を参照してください。

型の推論は、型メンバーのローカル変数として定義されている配列にのみ使用できます。 明示的な型定義がない場合、クラス レベルで配列リテラルで定義された配列は 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..を使用します。次のステートメント または For Each...次のステートメント は、配列の要素を反復処理します。 配列の上限がわからない場合は、 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 を使用しています...次のステートメントは、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

配列サイズのこの説明は、ジャグ配列には適用されません。 ジャグ配列とジャグ配列のサイズの決定については、「 ジャグ 配列」セクションを参照してください。

配列のサイズは、 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) は、可能な限り近い位置に要素をパックするか、自然なハードウェア境界上でそれらをすべて揃えるために、ストレージを割り当てることができます。 また、配列にはコントロール情報のストレージ オーバーヘッドが必要であり、追加されたディメンションごとにこのオーバーヘッドが増加します。

配列型

すべての配列にはデータ型があり、要素のデータ型とは異なります。 すべての配列に 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型の 1 次元配列であるInteger()を返します。 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型の 2 次元配列であるInteger(,)を返します。 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 番目の次元は日数を表し、月の日数は一様ではありません。 ジャグ配列は、配列の配列とも呼ばれ、このようなシナリオ向けに設計されています。 ジャグ配列は、要素も配列である配列です。 ジャグ配列とジャグ配列内の各要素は、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例外を危険にさらすことなく、コードはLengthRankなどのArray クラスのメンバーにアクセスするか、UBoundなどの Visual Basic 関数を呼び出す必要があります。

  • 特別なケースとして Nothing を確認する必要がないようにして、コードをシンプルに保つ必要があります。

  • コードは、長さ 0 の配列を 1 つ以上のプロシージャに渡す必要があるアプリケーション プログラミング インターフェイス (API) と対話するか、1 つ以上のプロシージャから長さ 0 の配列を返します。

配列の分割

場合によっては、1 つの配列を複数の配列に分割する必要があります。 これには、配列を分割するポイントを識別し、配列を 2 つ以上の個別の配列にスパッティングする必要があります。

このセクションでは、区切り記号に基づいて 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 メソッドも使用します。

このセクションでは、文字列配列を 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 名前空間のいずれかのクラスを使用できます。 ジェネリック コレクションでは、他のデータ型を追加できないように、型セーフが適用されます。

コレクションの詳細については、「 コレクション」を参照してください。

任期 定義
Visual Basic の配列ディメンション 配列内のランクと次元について説明します。
方法: Visual Basic で配列変数を初期化する 配列に初期値を設定する方法について説明します。
方法: Visual Basic で配列を並べ替える 配列の要素をアルファベット順に並べ替える方法を示します。
方法: ある配列を別の配列に割り当てる 配列を別の配列変数に割り当てる規則と手順について説明します。
配列のトラブルシューティング 配列を操作するときに発生するいくつかの一般的な問題について説明します。

こちらも参照ください