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 は幼稚園を表します)。

  • 要素に含まれている値は、その学年の生徒の数を表します。

Diagram showing an array of the numbers of students

次の例には、配列を作成して使用する 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 が最も優先度の高い型となります。 詳細については、「 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 クラスのメンバー (LengthRank など) にアクセスするか、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 で配列を並べ替える 配列の要素をアルファベット順に並べ替える方法について説明します。
方法: 配列を別の配列に代入する 配列を別の配列変数に代入するときの手順と規則を説明します。
配列のトラブルシューティング 配列を使用しているときに発生する一般的な問題について説明します。

関連項目