【初心者向け】エクセルVBAの配列とは?配列の使いどころを解説します
エクセルVBAの「配列」は、概念はわかりやすいけれど、使い道がわからないという方が多いようです。
そこで、このページでは、配列の基本的な使い方とともに、どういう用途で使うのかについて詳しく解説していきます。
この記事の目次
配列とは何か?
配列は、
- 複数の変数を一気に確保して
- どの変数を使うかを添え字で指定できる
機能のことをいいます。
後で、詳しく書きますが「添え字で指定できる」というところが大きなポイントです。
書式
次のように、通常の変数宣言の後に「( ... to ...)」という形の指定をします。
たとえば、
という変数宣言をすると、
- Data(1)
- Data(2)
- Data(3)
という3つの変数を一気に確保することができます。
添え字の「下限」は「0」「1」のどちらかにしましょう。
VBAの場合は、セル範囲を配列に格納すると「下限」が自動的に「1」になってしまうので、それに合わせてこだわりがなければ下限は「1」にすることをおすすめします。
下限の入力を省略した場合
Dim文で、下限の入力を省略して、
と変数宣言をすることもできます。
この場合には、モジュール冒頭の「Option Base」文の指定に応じて、下限は「0」または「1」に自動的に設定されます(「Option Base」の指定がない場合には、下限は「0」になります)。
たとえば、Option Baseの指定がない場合に「Dim Data(3)」と変数宣言をすると、下記のように4つ分の領域が確保されます。
- Data(0)
- Data(1)
- Data(2)
- Data(3)
具体例
次のマクロを実行すると、
A1セルに10、B1セルに20、C1セルに30が記入されます。
Sub ArrayTest()
Dim Data(1 to 3)
Data(1) = 10
Data(2) = 20
Data(3) = 30
Cells(1, 1).Value = Data(1) ' A1セルに10を記入
Cells(1, 2).Value = Data(2) ' B1セルに20を記入
Cells(1, 3).Value = Data(3) ' C1セルに30を記入
End Sub
配列の書式はわかったけれど、どう使えばいいの?
配列の勉強をしていると、配列の書式はわかった。でも、どう使えばいいのかピンと来ないというふうに感じる方が多いようです。
そこで、ここからは、配列の具体的な使い道を紹介しようと思います。
For~Nextと配列を組み合わせる
配列は、どの変数を使うかを「添え字」で指定できることが特徴です。
そして、この特徴は「For~Next」ループと非常に相性がいいのです。
実際の例として「新規シートを3枚挿入して、指定の名前に変更する」処理を書いてみようと思います。
- 配列を使わない場合
-
Sub AddSheet() Dim NewSheetNames1 NewSheetNames1 = "新シート1" Dim NewSheetNames2 NewSheetNames2 = "新シート2" Dim NewSheetNames3 NewSheetNames3 = "新シート3" Worksheets.Add after:=Worksheets(Worksheets.Count) '末尾にワークシートを挿入 ActiveSheet.Name = NewSheetNames1 Worksheets.Add after:=Worksheets(Worksheets.Count) '末尾にワークシートを挿入 ActiveSheet.Name = NewSheetNames2 Worksheets.Add after:=Worksheets(Worksheets.Count) '末尾にワークシートを挿入 ActiveSheet.Name = NewSheetNames3 End Sub
- 配列を使った場合
-
Sub AddSheetArray() Dim NewSheetNames(1 To 3) NewSheetNames(1) = "新シート1" NewSheetNames(2) = "新シート2" NewSheetNames(3) = "新シート3" Dim SheetNo As Long For SheetNo = 1 To 3 Worksheets.Add after:=Worksheets(Worksheets.Count) '末尾にシートを挿入 ActiveSheet.Name = NewSheetNames(SheetNo) '挿入したシートの名前を変更 Next End Sub
注目してほしいのは32行目です。
配列を使って「添え字」で、参照する変数を切り替えることができるため、「シート挿入」→「シート名変更」のロジックをFor~Nextループでまとめることができるのです。
If文の代わりに配列を使う
配列は、見方を少し変えると、添え字(=「整数」)を指定することで、対応する値を取得できるものだとも考えられます。
そのため、整数値に応じて、条件分岐するような場面で「If文の代わりに使う」ことができます。
たとえば、2行目~10行目まで、次のような計算をして、その集計結果をD11セルに表示させようと思います。
- B列が「1」のときは、D列の値を「足す」
- C列が「2」のときは、D列の値を「引く」
- 配列を使わない場合
-
Sub CalcBalance() Dim Balance Dim Row For Row = 2 To 10 If Cells(Row, 2).Value = 1 Then Balance = Balance + Cells(Row, 4).Value * 1 '入金データは残高に加算 Else Balance = Balance + Cells(Row, 4).Value * -1 '出金データは残高から減算 End If Next Cells(11, 4).Value = Balance '計算結果を表示 End Sub
配列を使ったときとの対比をわかりやすくするため、7行目、9行目の書き方がすこしわざとらしくなっています。
- 配列を使った場合
-
Sub CalcBalanceArray() Dim KubunToSign(1 To 2) KubunToSign(1) = 1 KubunToSign(2) = -1 Dim Balance Dim Row For Row = 2 To 10 Balance = Balance + Cells(Row, 4).Value * KubunToSign(Cells(Row, 2).Value) Next Cells(11, 4).Value = Balance '計算結果を表示 End Sub
26行目に注目してください。
If文で条件分岐をする代わりに、配列を使って同じロジックを実現しています。
文字列の結合
文字列を大量に結合する場合、1つ1つ文字列を結合していくより、配列とjoin関数を使って文字列結合をしたほが動作速度が速くなります。
- 配列を使わない場合
-
Sub ConcatStr() Dim Data As String Data = "A" Data = Data & ",B" Data = Data & ",C" Debug.Print Data ' A,B,C End Sub
- 配列を使った場合
-
Sub ConcatStrArr() Dim Parts(1 To 3) Parts(1) = "A" Parts(2) = "B" Parts(3) = "C" Dim Data Data = Join(Parts, ",") 'Partsの内容を「,」でつないで連結 Debug.Print Data ' A,B,C End Sub
どちらも結果は一緒なのですが、配列を使ったほうが動作速度が速くなります。
また、今回のように、文字列を結合するときに、文字列の間に「区切り文字」をはさんで連結をする場合には、配列+Join関数を使うほうがプログラムをわかりやすく書くことができます。
文字列の分割
文字列を、区切り文字ごとに分割して細切れの文字列を取得したいときにはSplit関数を使うと簡単に分割できます。
Split関数による分割結果は「配列」に格納されるため、配列を使う必要があります。
- 配列を使わない場合
-
※複雑なプログラムになるので略
- 配列を使った場合
-
Sub SplitArr() Dim Data Data = "A,B,C" Dim Parts '※要素数・型を指定しない Parts = Split(Data, ",") 'Dataの内容を「,」で分割。 '自動的にDim Parts(0 to 2)された状態になる Debug.Print Parts(0) 'A ※添え字は常に0始まり Debug.Print Parts(1) 'B Debug.Print Parts(2) 'C End Sub
Split関数を使うときには、その結果を入れる変数は、Dim文で要素数・型を指定しないことに注意してください。
実際、先ほどのソースコードの5行目を見て見ると、「Dim Parts」というように「要素数」「型」のどちらも指定していないことがわかります。
そして、Split関数を使った段階で、変数Partsは、自動的に「配列」になります。
VBAの仕様で、Split関数で作った配列は、必ず、添え字が「0」で始まる配列になりますので、ご注意ください。
2次元配列とは何か?
配列は、添え字を「複数」取ることもできます。
よく使われるのが、添え字を2つ使う「2次元配列」です。
書式
括弧の中を「,」で区切って「... to ...」という指定を「2つ」行います。
たとえば、
という変数宣言をすると、
- Data(1,1)
- Data(1,2)
- Data(2,1)
- Data(2,2)
- Data(3,1)
- Data(3,2)
という6つの変数を一気に確保することができます。
2次元配列の使い道
2次元配列は、複数セルのデータを変数に取り込みたいときに便利です。
「セル」と「配列」の書き方がそっくりなので便利
次のマクロを実行すると、A1セル~B3セルの内容が、D1セル~E3セルに転記されることになります。
Sub RangeCopy()
Dim Data(1 To 3, 1 To 2)
Data(1, 1) = Cells(1, 1).Value ' A1セルの内容を代入
Data(1, 2) = Cells(1, 2).Value ' B1セルの内容を代入
Data(2, 1) = Cells(2, 1).Value ' A2セルの内容を代入
Data(2, 2) = Cells(2, 2).Value ' B2セルの内容を代入
Data(3, 1) = Cells(3, 1).Value ' A3セルの内容を代入
Data(3, 2) = Cells(3, 2).Value ' B3セルの内容を代入
Cells(1, 4).Value = Data(1, 1) ' D1セルに10を記入
Cells(1, 5).Value = Data(1, 2) ' E1セルに20を記入
Cells(2, 4).Value = Data(2, 1) ' D2セルに30を記入
Cells(2, 5).Value = Data(2, 2) ' E2セルに40を記入
Cells(3, 4).Value = Data(3, 1) ' D3セルに50を記入
Cells(3, 5).Value = Data(3, 2) ' E3セルに60を記入
End Sub
先ほどのプログラムを見ると、Dataを2次元配列にしたおかげで、CellsとDataの書き方がそっくりになりました。
このように、2次元配列は「セル範囲を丸ごと読み込んだり、丸ごと書き込む」用途に使うと、プログラムがわかりやすく書けます。
セル範囲への読み込み、書き込みを高速にする
先ほどのプログラムを改良すると、さらにシンプルに書くことができ、しかも、実行速度を速くすることができます。
Sub RangeCopy2()
Dim Data '※要素数・型を指定しない
Data = Range("A1:B3").Value ' A1セル~B3セルの内容をDataにコピー
' 自動的にDim Data(1 to 3,1 to 2)が実行された状態になる
Range("D1:E3").Value = Data ' D1セル~E3セルにDataの内容をコピー
End Sub
先ほどとまったく同じ意味のプログラムですが、一気に行数が短く・シンプルになりました。
しかも、実行速度もかなり速くなります。
実は、Range(あるいはCells)を呼び出す回数が少なくなればなるほど実行速度は速くなります。
改良前と改良後で呼び出す回数を比較すると改良後のほうが回数が少ないため、改良後のプログラムのほうが動作速度が速くなるのです。
- 改良前:12回(Cellsの読み込みが6回、書き込みが6回)
- 改良後:2回(Rangeの読み込みが1回、書き込みが1回)
今回程度のプログラムであれば体感できる差は付きませんが、セルへの読み書きが多いと、場合によっては、数十倍近く動作速度が変わります。
実行速度が遅いと感じたら、セルの読み書きは複数セルをまとめて行うように心がけてみてください。
セル範囲を読み書きするときに気をつけるべき点
セル範囲と2次元配列との間で、データの読み書きをするときには、何点か気をつけないといけないポイントがあります。
Dim文では何も指定しない
Dim文で配列として変数宣言をしてしまうとうまく動かず、エラーが出ます。
少し気持ち悪いかもしれませんが、変数宣言時は添え字の下限・上限の指定をせず、Variant型変数として宣言をしてください。
Dim Data
Data = Range("A1:B3").Value ' A1セル~B3セルの内容をDataにコピー
型を何も指定しなければ、自動的にVariant型になりますので、上記のように変数名のみ指定するのがおすすめです。
少し気持ち悪いかもしれませんが、3行目の代入後は2次元配列として使えるようになります。
添え字は1から始まる
セル範囲を変数に代入した段階で、自動的に2次元配列になるわけですが、そのときの添え字は1から始まります。
セル範囲を丸ごと変数に代入する場合、添え字を「0」始まりにすることはできませんので、気をつけてください。
一方で、前述したSplit関数を使うと、添え字が「0」始まりになってしまいます。
このように、VBAでは、言語仕様として、添え字を「0始まり」「1始まり」のどちらかに統一することはできません。
気持ち悪いですが、仕方がないと思ってあきらめてください。
配列を使ううえで知っておいたほうがいい機能
配列の添え字の下限、上限を調べる
- LBound関数:配列の添え字の「下限」
- UBound関数:配列の添え字の「上限」
を調べることができます。
書式
具体例(Splitと組み合わせる)
Sub SplitArr2()
Dim Data
Data = "A,B,C"
Dim Parts '※要素数・型を指定しない
Parts = Split(Data, ",") 'Dataの内容を「,」で分割。
'自動的にDim Parts(0 to 2)された状態になる
Dim C As Long
For C = LBound(Parts) To UBound(Parts)
Debug.Print Parts(C)
Next
End Sub
このプログラムは、文字列の分割のところで紹介したプログラムを、For文とLBound、UBoundを使って書き換えたものです。
Splitを使うと、プログラムを実行してみるまで、配列の添え字の上限が決まらないため、事前に、For文の「To」の指定ができません。
そこで、UBoundを使うことで、Splitで分割されたデータの個数が変わっても、プログラムの変更をする必要がなくなります。
また、LBoundを使うことで、配列の添え字の「下限」を意識する必要性が少なくなります。
2次元配列の添え字の下限、上限を調べる
2次元配列の場合には、次のような書式で、配列の添え字の下限、上限を調べることができます。
書式
次のように、配列名の後に、添え字の下限・上限を知りたい「次元」を入れると、それぞれの次元の下限・上限を調べることができます。
あるいは
LBound(配列名, 2)
あるいは
UBound(配列名,2)
具体例
セル範囲への読み込み、書き込みを高速にするで紹介したプログラムに変更を加えてみようと思います。
「A1~B3セル」の内容を「D1~E3セル」にコピーするときに、値を2倍にしたうえで転記してみます。
Sub RangeCopy3()
Dim Data
Data = Range("A1:B3").Value ' A1~B3セルの内容をDataにコピー
' 自動的にDim Data(1 to 3,1 to 2)が実行された状態になる
Dim Row
Dim Column
For Row = LBound(Data, 1) To UBound(Data, 1) '1次元目のループ
For Column = LBound(Data, 2) To UBound(Data, 2) '2次元目のループ
Data(Row, Column) = Data(Row, Column) * 2 '内容を2倍する
Next
Next
Range("D1:E3").Value = Data ' D1~E3セルには、A1~B3セルの2倍の値が代入される
End Sub
For~Nextループの二重ループで、ループ変数の初期値、最終値にLBound、UBoundで得た値を使っています。
まとめ
配列を、使わなくても最低限のプログラムは組めます。
ただ、配列を使うことで、次のようなメリットがあります。
- For~Next文が使えて、プログラムの重複が防げる
- 処理の高速化ができる
VBAでのプログラミングに慣れてきたら、配列も使えるように練習してみてください。
次の記事はこちら↓
【初心者向け】エクセルVBAのRangeとCellsの使い分け方は?