ゆんの業務改善ブログ

①生産性向上 ②業務改善 ③自動化 について情報発信しています。VBAプログラムは本当の初心者から他のアプリケーションを呼び出して使う上級者的な使い方まで幅広いレベルで解説していきます。

VBA 配列を徹底的に解説する (全5回) ③静的配列の初期化と実務的なサンプル

VBAの静的配列の初期化を具体的で実務的なサンプルを使って解説します。配列が初期化できると実務的に便利なことが多いです。難しくないので、順番に見て行きましょう。

目次

静的配列の初期化と実務的なサンプルを解説する

配列の初期状態とは

配列の初期化を解説するために、まず始めに配列の初期状態はどうなっているのかを確認します。標準モジュールに配列を作成するサブプロシジャを記述します。

Sub 配列を作成する()
    
    Dim arr(4) As Variant
    
End Sub

もっとも単純な例で確認します。F8で一行ずつ実行してローカルウィンドウを確認します。
f:id:mutable_yun:20190922110318p:plain

値の所を見ると、Empty 値 と書いてあります。””(長さ0の文字列)でも数字の0でもNothingでもありません。Emptyという「空の状態」という状態を表す特殊な値が入っています。

静的配列の初期化を行う

配列を宣言したばかりの状態では各要素はEmpty(空の状態)となっていることが分かりました。矛盾している様に思うかもしれませんが、各要素にEmpty(空の状態)が格納されている、と考えると良いです。

静的配列の各要素を初期化する

初期状態でEmptyが格納されていると言うことは、逆にEmptyを格納すれば初期化できることになります。

Sub 静的配列の要素の初期化1()

    Dim arr(4) As Variant
    
    arr(0) = "Good Morning"
    arr(1) = "Hello"
    arr(2) = "Good Afternoon"
    arr(3) = "Good Evening"
    arr(4) = "Good Night"
   
    arr(2) = Empty
    
End Sub

f:id:mutable_yun:20190922111256p:plain
arr(2)にEmptyを設定することにより初期化
ポイントはEmpty””がついていないことです。Emptyと言う文字列ではなく、Emptyという特別な値を格納しているので、 arr(2) = "Empty"ではなく、 arr(2) = Emptyとなります。

静的配列をループで初期化する

静的配列は同じグループの複数パラメータを一つにまとめておくのに便利な変数であると言えます。そのため、配列を初期化したいときは、どれかの要素を一つだけ初期化するというより、全部初期化したい場面の方が多いです。

たとえばエクセルシートに仕入れ先一覧表があって、一行ごとに仕入れ先情報が格納されている。一行ごとにその仕入れ先情報を配列に格納し、別シートで何らかの作業を行い、その作業が終わったら配列を初期化して、次の行の仕入れ先のデータに移る、と言った具合です。

それでは、このような場合に静的配列を初期化するにはどうすれば良いのでしょうか。結論としては静的配列そのものをEmptyにする事はできません。実際に確認します。

Sub 実験_配列そのものをEmptyにできるのか()
    
    Dim arr(4) As Variant
    
    arr(0) = "Good Morning"
    arr(1) = "Hello"
    arr(2) = "Good Afternoon"
    arr(3) = "Good Evening"
    arr(4) = "Good Night"
    
    arr = Empty '配列そのものにEmptyを格納することはできない為、ここでエラーとなる
    
End Sub

f:id:mutable_yun:20190922112154p:plain
コンパイルエラーが発生した

今回は一行ごとの文法のミスはありません。なぜならば、プログラムの一行一行を見ればarrを配列とは判断できず、arr = Emptyの部分はVariant型の変数の値をEmptyに設定しようとしただけに見えるためです。このため、プログラミング中の文法チェック機能ではエラーは出ませんでしたが、プログラム実行前のコンパイルでエラーとなるのです。

つまり、実行を押した瞬間にコード全体を見ると配列として宣言した変数arrにEmptyをいれようとしたことがわかったのでコンパイルエラーとなりました。(カッコをつける事が配列である事の宣言でしたね)

今回のエラーはarr = Emptyの部分でエラーが発生します。つまり、arrは配列として宣言してそのものの実態があるのにそれをEmptyにはできない、と言う事です。

私たちがここでやりたいことは、arrの要素をすべてEmptyにしたい、と言う事であって、arrそのものをEmptyにしたわけではありません。そこで、ループを使って、全ての要素をEmptyにします。各要素にEmptyを格納していくイメージでOKです。

正しい初期化のサンプルは下記の通りです。

Sub ループを使って初期化する()
    
    Dim arr(4) As Variant
    Dim i As Long
    
    arr(0) = "Good Morning"
    arr(1) = "Hello"
    arr(2) = "Good Afternoon"
    arr(3) = "Good Evening"
    arr(4) = "Good Night"
    
    For i = 0 To 4
        arr(i) = Empty
    Next i
    
    Stop
    
End Sub

これで無事に初期化できます。実行結果は下のイミディエイトウィンドウの通りです。

静的配列を初期化するにはループを使う
ループで初期化した実行結果

LBound関数とUBound関数

今回は静的配列なので一番小さなインデックスと一番大きなインデックスの数値がいくつか分かっています。なので数字で直接ループの範囲を指定しても構いません。

しかし、今後業務の内容が変更になり、配列に格納したいパラメータ(値)の数が変わることも想定して、配列の一番小さいインデックスと一番大きなインデックスを取得する関数を使う方が好ましいでしょう。このことに対応したプログラムは以下のようになります。

Sub LBoundとUBound関数()
    
    Dim arr(4) As Variant
    
    Debug.Print LBound(arr)
    Debug.Print UBound(arr)
    
End Sub

実行結果

 0 
 4 

LBound関数、UBound関数の使い方は引数にインデックスの最小値や最大値を取得したい配列名を入れるだけです。

LBound関数とUBound関数は、実はもう一つ引数をとることができます。しかし、話が複雑にならないよう今回は割愛します。気になる方は、VBA 配列を徹底的に解説する (全5回) ④多次元配列で詳しく解説していますので参考にしてみて下さい。

さて、インデックスの最小値と最大値が取得できたので後はFor~Next文で一つずつEmptyを入れて行きます。先ほどの、サンプルプロシジャのインデックスの下限と上限をLBound関数とUBound関数で取得します。

 Sub ループで配列の各値を初期化する()
    
    Dim arr(4) As Variant
    
    arr(0) = "Good Morning"
    arr(1) = "Hello"
    arr(2) = "Good Afternoon"
    arr(3) = "Good Evening"
    arr(4) = "Good Night"
    
    Dim i As Long
    
    For i = LBound(arr) To UBound(arr)
        arr(i) = Empty
    Next i
    
End Sub

いつものようにF8で一行ずつ実行していくと、プログラムが実行されて一つずつ配列の要素がEmpty値に置き換わっていく様子が観察できます。。

f:id:mutable_yun:20190922113822p:plain
結果

配列arrの各要素に値が順に格納され、その後、順にEmptyに戻っていっていますね。

実務的なサンプルを作成する

実務的なサンプルの例に移ります。

f:id:mutable_yun:20190921184841p:plain
売上データサンプル

今回は上のようなデータをサンプルとして考えます。これは各支店の売上のデータのイメージです。このデータを分析するために、

  1. 一行分のデータを配列に格納する
  2. 何らかの処理を行う
  3. 配列を初期化する
  4. 次の行に移る

これを最終行まで繰り返します。

Sub 実務的サンプル()
    
    '>下準備で必要な変数や定数を用意しておく
    Const 最初の行rw As Long = 2
    Dim 最終行rw As Long
    
    Const 最初の列clm As Long = 1
    Const 最後の列clm As Long = 4
    
    Dim 売上データ行arr(最初の列clm To 最後の列clm) As Variant
    
    Dim i As Long 'ワークシートの最初の行から行方向にカウントアップする
    Dim j As Long '売上データを格納するためのカウントアップ
    '<下準備ここまで
    
    最終行rw = Cells(Rows.Count, 1).End(xlUp).Row
    
    For i = 最初の行rw To 最終行rw '一番大きなループ。行方向にループする
        
        '>配列にデータを格納
        For j = 最初の列clm To 最後の列clm
            売上データ行arr(j) = Cells(i, j)
        Next j
        '<配列にデータを格納
        
        '>メインの作業
        'ここにメインの作業を書く。Callで別に記述したプロシジャを呼び出すのがおすすめ
        '<メインの作業
        
        '>次の行に移る前に配列を初期化する
        For j = 最初の列clm To 最後の列clm
            売上データ行arr(j) = Empty
        Next j
        '<次の行に移る前に配列を初期化する
    Next i
    
End Sub

はい、できました。便利ですね!これからは配列をうまく使ってコードをシンプルにし、ワークシートへの参照回数を減らしていきましょう。ワークシートへの参照回数を減らすことはマクロの高速化にもつながります。ぜひとも配列をマスターしてプログラムの高速化を図りましょう。

静的配列の初期化と実務的なサンプルまとめ

  • 静的配列は一気には初期化できない
  • 静的配列はループで初期化する
  • 配列のインデックス番号の下限値と上限値はLBound関数とUBound関数を使って取得できる

<関連記事>