2016-09-30

VBA配列基礎

通常の変数は1つの変数に1つの値しか格納できませんが、配列を利用すれば一つの変数に同じデータ型の複数の値を格納することができます。このエントリーでは、VBAで配列を利用するための基本事項をご紹介致します:)

配列とは

まず、配列とは何かを知っておきましょう:)

配列の定義

VBA のヘルプには以下のようにあります。

配列

定義済みの同じデータ型を持つ要素の集合。各要素には順番にインデックス番号が付けられます。各要素を識別するには、配列名とインデックス番号を使います。ある要素に変更を加えても、他の要素には影響しません。

冒頭でも述べましたが、配列は一つの変数に複数の値を保持します。配列に含まれる値はそれぞれ『要素』と呼ばれます。各要素には『インデックス番号』が割り振られ、対応する『インデックス』を指定して参照することができます。インデックスは通常『0』から始まります。一つ目の要素は『要素0』、ふたつ目の要素は『要素1』といった感じです。配列を構成している要素の数を『要素数』と表現します。

どんなとき使うの?

ではこの配列はいったいどんな状況で使うのでしょうか?

例えば、1ヶ月分の天気を管理するプログラムがあったとします。『一日は晴れ』『二日はくもり』のように31日分の天気を格納しなければならないため、配列を使用しないと31個もの変数を定義しなければなりません。これは定義するだけでも大変ですし、データの取り扱いも難しくなってしまいます。

こんなプログラム考えただけでも触りたくないですよね...

一方、配列を使えば変数の宣言はひとつだけです。データの取り扱いもインデックスを使って簡単に行えます。

    '天気情報変数定義
    Dim weather01 As String
    Dim weather02 As String
    Dim weather03 As String
    ・・・
    Dim weather31 As String
    '天気情報変数定義
    Dim weather(30) As String

上記の例をご覧頂ければ一目瞭然ですが、配列を使用することによってだいぶスッキリしているのがわかります。
このように、例に挙げた『1ヶ月の天気』のような同じデータ型の繰り返しの項目を取り扱う時に配列はその効果を発揮します。

1ヶ月分の天気

※カッコ内の数字はインデックス番号

配列の宣言は例のように「変数名(要素数)」の形式で記述します。31日分の天気情報を格納するのに例では要素数の定義が30となっていますが、先述の通り配列のインデックスは0から始まるため、0~30の31個の配列要素が使用可能となります。
定義などの詳細は後述します:)

配列の次元

配列には『次元』という概念があります。
先ほどの1ヶ月分の天気を管理するプログラムを例に見てみると、純粋に日にちの繰り返しだけなので『一次元配列』となります。

では1年分の天気を管理するにはどうしたらいいでしょうか。

1ヶ月分であれば要素数31の配列があれば事足りますが、1年分となると1ヶ月の配列が12個、つまり『12(月数)×31(日数)』の要素が必要になります。このような『繰り返し×繰り返し』の性質を持つ配列を総じて『多次元配列』といいます。言わば『配列の配列』です。例に挙げた1年分の天気なら『二次元配列』ですね。これが複数年、例えば5年分の天気を管理するとなると 『5(年数)×12(月数)×31(日数)』となるので『三次元配列』となります。

1年分の天気

※カッコ内の数字はインデックス番号

静的配列と動的配列

VBAで宣言できる配列は静的配列動的配列の2種類に大別されます。まずはこの2つをしっかりと理解しておきましょう。

静的配列とは

静的配列とは、配列変数宣言時にその要素数も同時に宣言し、宣言後は要素数を変更できない配列の事を言います。つまり、初めに「要素数3」と定義したら後から要素数を5に増やしたり、逆に2に減らしたりできないって事です。なお、VBAのヘルプでは静的配列を「固定長配列」と表現していることもありますが、このエントリーでは「静的配列」で統一しています。

静的配列を宣言する際のリファレンスです。

構文:{ Dim | Static | Public | Private } arrayname ([lowerbound to ] upperbound [,[lowerbound to ] upperbound...]) [As type]

指定項目 指定 内容
arrayname 必須 配列変数の名前を指定します。
lowerbound 省略可 配列の下限を明示的に定義する場合に指定します。省略した場合は、Option Baseステートメントで指定した0または1が配列の下限となります。Option Baseの宣言がない場合は0が配列の下限となります。
upperbound 必須 配列の上限を指定します。多次元配列を定義する場合は [lowerbound To] upperbound の形式をカンマで区切って次元数分定義します。
type 省略可 通常の変数と同じように配列変数の型を指定します。 

以下に静的配列を宣言するサンプルを示します。変数名のあとに要素の下限・上限をカッコ付きで記述します。

    '要素数4(0,1,2,3)のString型の配列定義
    Dim array1(3) As String
    '要素数3(2,3,4)のLong型の配列定義
    Dim array2(2 To 4) As Long
    '要素数3,2の2次元配列定義
    Dim array3(2, 1) As Long

動的配列とは

動的配列とは、配列変数宣言時に要素数を明示的に宣言せず、宣言後に配列の要素数を動的に変更することができる配列です。動的配列の要素数は後述のReDimステートメントで再定義します。

動的配列を宣言する際のリファレンスです。

構文:{ Dim | Static | Public | Private } arrayname () [As type]

指定項目 指定 内容
arrayname 必須 配列変数の名前を指定します。
type 省略可 通常の変数と同じように配列変数の型を指定します。 

以下に動的配列を宣言するサンプルを示します。静的配列と違い要素数(カッコの中の数字)を定義せず、変数名のあとには空のカッコのみ記述します。

    '要素数(下限・上限)を宣言しない
    Dim array1() As String
    Dim array2() As Long

ReDimステートメント

要素数を省略して定義された動的配列はReDimステートメントを使用して下限・上限、次元を再定義しメモリ領域の再割り当てを行います。

ReDimステートメントは以下の構文で使用します。Preserveキーワード以外は静的配列の構文と同じですね。

構文:ReDim [Preservearrayname ([lowerbound to ] upperbound [,[lowerbound to ] upperbound...]) [As type]

指定項目 指定 内容
preserve 省略可 要素数を変更する際に、配列に格納されている値を保持したままにする場合に指定します。
arrayname 必須 配列変数の名前を指定します。
lowerbound  省略可 配列の下限を明示的に定義する場合に指定します。省略した場合は、Option Baseステートメントで指定した0または1が配列の下限となります。Option Baseの宣言がない場合は0が配列の下限となります。
upperbound 必須 配列の上限を指定します。多次元配列を定義する場合は [lowerbound To] upperbound の形式をカンマで区切って次元数分定義します。但し、ReDimステートメントで上限を変更できるのは最後の次元のみです。
type 省略可 通常の変数と同じように配列変数の型を指定します。 省略した場合は変数宣言時のデータ型になります。

以下にRedimステートメントを使用するサンプルを示します。

    'String型の動的配列を宣言
    Dim aryDynamic() As String
    'Redimで配列を再定義
    ReDim aryDynamic(3) As String
    'Redimで2次元配列を再定義
    ReDim aryDynamic(3, 3) As String

値の格納と参照

静的配列と動的配列を理解したところで、実際に配列を使用してイメージを掴んでみましょう:)

配列は複数の値を保持できます。それぞれの値の格納・参照はインデックスを使用して行います、↓こんな感じに。

    '要素数3(0,1,2)の配列を宣言
    Dim aryStatic(2) As String
    'インデックスを使用して値を格納
    aryStatic(0) = "ラス"
    aryStatic(1) = "ペニー"
    aryStatic(2) = "白チョコ"
    '参照する場合もインデックスを使用
    Debug.Print "要素0:" & aryStatic(0)
    Debug.Print "要素1:" & aryStatic(1)
    Debug.Print "要素2:" & aryStatic(2)

このコードを実行するとイミディエイトウィンドウには以下のように表示されます。

要素0:ラス
要素1:ペニー
要素2:白チョコ

配列を参照する場合はFor Nextステートメント、通称Forループを使用する事が多いです。以下のコードを実行すると先ほどと同じ内容がイミディエイトウィンドウに出力されます。

    'Forループで参照
    Dim i As Long
    For i = 0 To 2
        Debug.Print "要素" & i & ":" & aryStatic(i)
    Next

例では静的配列を使用しましたが、動的配列でも格納・参照の方法は同じです。

値を保持するPreserveキーワード

ReDimステートメントで動的配列を再定義すると、それまで配列の内容はクリアされてしまいます。

以下の例では要素数3の動的配列aryDynamicに値を格納した後、ReDimステートメントを使用して要素数を4に拡張しまいます。Preserveキーワードの有無で値がクリアされるか保持されるかの違いがわかります。

▼1つ目のStopの時点では値が格納されています

array-basic-preserve-1

ReDimで配列を拡張するとそれまで格納されていた値がクリアされてしまう

array-basic-preserve-2

Preserveキーワードを指定すれば値をクリアすることなく配列を拡張することができます。

▼Preserveキーワードを指定すると値を保持したまま配列を拡張できる

array-basic-preserve-3

配列に必要なメモリ容量

まず、配列は要素数、データ型に関わらず20バイトのメモリを必要とします。さらに、次元ごとに4バイトのメモリを必要とします。それぞれの要素についてはデータ型に必要なメモリ容量が要素数分必要です、、、って、自分で書いててもわかりづらい事この上ないですね(^^;

要するに、配列に必要なメモリ容量は以下の数式で求めることができます。

20 + (次元数 * 4) + (要素数 * データ型に必要なメモリ容量)

例えば、要素数3のLong型の1次元配列は

20 + (次元数[1] * 4) + (要素数[3] * Long型に必要なメモリ容量[4])
=20 + (4) + (12)
=36バイト

となります。

1次元目の要素数が3、2次元目の要素数が10のInteger型の2次元配列は

20 + (次元数[2] * 4) + (要素数[3 + 10] * Integer型に必要なメモリ容量[2])
=20 + (8) + (26)
=54バイト

となります。

まとめ。

配列はプログラミングに置いてとても重要で、ある程度の規模のプログラムになると必ずと言っていい程配列が登場します。
特に Excel のワークシートは行・列の二次元配列なので、Excel VBA では特に重要です。このエントリーで述べていることは配列の基礎の基礎になりますのでしっかりと理解して配列を使いこなしましょう:)

ご不明点などありましたらお気軽にお問合せくださいまし:D

HAYs

タグ: ,
関連記事

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です