配列を使うとデータに順序を持たせてまとめることができます。
例えば、以下の表をまるごと配列にすることで、「何行目の何列目のデータ」と指定して簡単に参照できるようになります。
配列について
実際に配列を使ってみましょう。「りんご」の各データを配列に代入し、for文でセルに出力してみます。
Dim ws As Worksheet 'ワークシートのオブジェクト変数を宣言
Set ws = ThisWorkbook.Sheets("Sheet1")
Dim appleArray(4) As Variant 'Variant型でりんごの配列を宣言
appleArray(0) = "りんご"
appleArray(1) = 100
appleArray(2) = 3
appleArray(3) = 300
appleArray(4) = "1000未満"
For i = 1 To 5 '7行目にりんごの配列を出力
ws.Cells(7, i).Value = appleArray(i - 1)
Next i
配列は、変数名の後にかっこ()内に番号を付けることで、順序を持った変数として利用できます。このかっこ内の番号のことを「インデックス」といいます。基本的に配列のインデックスは0から始まります。
上の例だと、appleArrayという配列を準備し、0~4つの計5つの箱を用意してそれぞれに値を代入しています。for文で配列のかっこ内の数値をカウントアップしながらループさせることで、簡単にセルに出力できます。
Variant型について
また、以下のようにしれっとデータ型に「Variant型」を使っていますが、これはどんなデータ型でも代入できる便利な型です。特に配列の場合、整数や文字列が混在するのでよく使います。
Dim appleArray(4) As Variant 'Variant型でりんごの配列を宣言
配列の宣言
配列は以下のように宣言できます。配列の1つ1つのデータのことを「要素」といい、かっこ内の数値のことをインデックスといいます。また、指定しない限り配列のインデックスの開始は0になります。
Dim 配列名(要素数-1) As データ型
例えば、5つの要素を持つ配列「appleArray」を作りたい場合、「(要素数5-1)」で宣言時は「(4)」とします。
Dim appleArray(4) As Varient
また、以下のように開始インデックス番号を指定して宣言もできます。下の例だと開始が1から5までの配列となります。
Dim appleArray(1 To 5) As Variant
ちなみに、for文で出力するときに開始インデックスが0だと、以下のようにappleArrayのインデックスを「i-1」とする必要がありました。
For i = 1 To 5 'Dim appleArray(4) As Varientで宣言した場合
ws.Cells(7, i).Value = appleArray(i - 1)
Next i
一方、開始インデックスを1にすると、セルの列番号とappleArrayのインデックスを「i」と一致させられるので、不慣れな内はコードを書いていて楽になります。
Dim appleArray(1 To 5) As Variant 'りんごの配列
appleArray(1) = "りんご"
appleArray(2) = 100
appleArray(3) = 3
appleArray(4) = 300
appleArray(5) = "1000未満"
For i = 1 To 5 'Dim appleArray(1 To 5) As Variantで宣言した場合
ws.Cells(7, i).Value = appleArray(i)
Next i
配列の要素数を変数で指定(動的配列)
配列の要素を変数で指定することもできます。動的に配列の要素数を変えられるので、このような配列を動的配列といいます。例えば、要素数を変数 nとして動的配列を宣言すると以下のようになります。
Dim n As Integer '配列の要素数
n = 5
Dim appleArray() As Variant 'りんごの配列
ReDim appleArray(1 To n) 'ReDim appleArray(n - 1)といった宣言も可
上コードのように「Dim appleArray() As Variant」と宣言した後に、「ReDim appleArray(1 To n)」と変数を使って宣言します。
配列の要素に代入
インデックス番号を指定して各要素に代入
配列の要素に代入ですが、下記のようにインデックス番号を指定して各要素に代入できます。
Dim ws As Worksheet 'ワークシートのオブジェクト変数を宣言
Set ws = ThisWorkbook.Sheets("Sheet1")
Dim appleArray(4) As Variant 'Variant型でりんごの配列を宣言
appleArray(0) = "りんご"
appleArray(1) = 100
appleArray(2) = 3
appleArray(3) = 300
appleArray(4) = "1000未満"
Array関数を使用して代入
Array関数を使って変数に配列を代入することもできます。メリットとして、先ほどよりコードを書く量が減ります。
Dim appleArray As Variant 'りんごの配列
appleArray = Array("りんご", 100, 3, 300, "1000未満")
2次元配列
Excelの表に例えると、先ほどまでの配列は1行のデータの集まりでした。これを1次元配列といいます。
それに対して2次元配列は、複数の行と列の配列…つまり下のような表そのものが配列になったイメージです。
2次元配列の宣言
2次元配列では、かっこ内にインデックスを2つ指定して「,」で区切ります。区切ったインデックスはそれぞれ(行, 列)を意味します。宣言や代入の仕様は1次元配列とほぼ同様で、基本的にインデックスは0が開始となります。
Dim 配列名(行-1, 列-1) As データ型
また、1次元配列と同様に開始インデックスを以下のように指定できます。
Dim fruitArray(1 To 3, 1 To 5) As Variant '3行5列の2次元配列
2次元配列の要素に代入
2次元配列の各要素は以下のように指定できます。下の例では開始インデックスを1としているので、例えばfruitArray(1, 2)は1行目の2列目を意味します。
Dim ws As Worksheet 'ワークシートのオブジェクト変数を宣言
Set ws = ThisWorkbook.Sheets("Sheet1")
Dim fruitArray(1 To 3, 1 To 5) As Variant '果物の2次元配列
fruitArray(1, 1) = "果物"
fruitArray(1, 2) = "価格"
fruitArray(1, 3) = "個数"
fruitArray(1, 4) = "合計金額"
fruitArray(1, 5) = "合計金額が1000円以上"
fruitArray(2, 1) = "りんご"
fruitArray(2, 2) = 100
fruitArray(2, 3) = 3
fruitArray(2, 4) = 300
fruitArray(2, 5) = "1000未満"
fruitArray(3, 1) = "なし"
fruitArray(3, 2) = 90
fruitArray(3, 3) = 4
fruitArray(3, 4) = 360
fruitArray(3, 5) = "1000未満"
For i = 1 To 3 '7行目に出力
For j = 1 To 5
ws.Cells(i + 6, j).Value = fruitArray(i, j)
Next j
Next i
2次元配列は慣れるまで難しいですが、for文で出力された結果と各要素を照らし合わせると分かりやすいと思います。
配列リテラルを使った代入
以下のコードのように、大括弧[]を使ってつくる配列を配列リテラルといいます。膨大な数の要素に、for文やその他の方法を使わずに代入させるならこちらが便利でしょうか。
この指定で配列を作ると、開始インデックスは1になります。
Dim fruitArray As Variant '果物の2次元配列
fruitArray = [{"りんご",100,3,300,"1000未満";"なし",90,4,360,"1000未満";"ぶどう",200,5,1000,"1000以上10000未満";"すいか",2000,6,2000,"10000以上"}]
配列リテラルに関しては下のリンクへ
2次元配列をRangeオブジェクトで取得
セル範囲をオブジェクトで扱えるRangeオブジェクトを使うと非常に便利です。Rangeオブジェクトは以下のように使います。
Range(開始セル, 終了セル)
例えばExcelでセルを範囲選択する際、下図のようにCell(1, 1)を選択し、shiftキーを押しながらCell(5, 3)を選択しますね。
上図のような5行×3列のRangeオブジェクトを表現したい場合、以下のコードように開始セルをCell(1, 1)、終了セルをCell(5, 3)とすることで、5行×3列のセル範囲のオブジェクトとなります。注意点として開始・終了セルに「.Value」は不要です。
Range(Cells(1, 1), Cells(5, 3)) '5行×3列のセル範囲
Rangeオブジェクトを使って2次元配列を取得し、出力してみます。このとき開始インデックスは1になります。
Dim ws As Worksheet 'ワークシートのオブジェクト変数を宣言
Set ws = ThisWorkbook.Sheets("Sheet1")
Dim fruitArray As Variant '果物の2次元配列
fruitArray = Range(ws.Cells(1, 1), ws.Cells(5, 5))
For i = 1 To 5
For j = 1 To 5
ws.Cells(i + 6, j).Value = fruitArray(i, j) '7行目に出力
Next j
Next i
LBoundとUBound
配列のインデックス番号の最大値または最小値を返してくれる関数です。
- LBound→配列のインデックス番号の一番小さい値を返す
- UBound→配列のインデックス番号の一番大きい値を返す
配列の変数をかっこ内に記述すると、インデックス番号の最大値または最小値を返してくれます。
Dim arr1(3) As Variant
MsgBox LBound(arr1) '0と出力
MsgBox UBound(arr1) '3と出力
Dim arr2(1 To 3) As Variant
MsgBox LBound(arr2) '1と出力
MsgBox UBound(arr2) '3と出力
2次元配列の場合、配列の変数の後に「,」で区切り、「1」だと行、「2」だと列のインデックス番号の最大値または最小値を返します。
Dim arr1(3, 5) As Variant
MsgBox LBound(arr1, 1) '0と出力
MsgBox UBound(arr1, 1) '3と出力
MsgBox LBound(arr1, 2) '0と出力
MsgBox UBound(arr1, 2) '5と出力
Dim arr2(1 To 3, 1 To 5) As Variant
MsgBox LBound(arr2, 1) '1と出力
MsgBox UBound(arr2, 1) '3と出力
MsgBox LBound(arr2, 2) '1と出力
MsgBox UBound(arr2, 2) '5と出力
例えば、for文でループを回すときに以下のように使えます。
Dim fruitArray As Variant '果物の2次元配列
fruitArray = [{"りんご",100,3,300,"1000未満";"なし",90,4,360,"1000未満";"ぶどう",200,5,1000,"1000以上10000未満";"すいか",2000,6,2000,"10000以上"}]
For i = LBound(fruitArray, 1) To UBound(fruitArray, 1) 'for文で7行目に2次元配列を出力
For j = LBound(fruitArray, 2) To UBound(fruitArray, 2)
ws.Cells(i + 6, j).Value = fruitArray(i, j)
Next j
Next i
要素数を変数で指定すると、何回 for文を回したらよいのかコードに数値で書けないので、これらの関数が非常に便利です。
最後に
2次元配列は使い慣れるのに非常に苦労しますが、慣れるとコードを書くのも楽になってマクロの処理速度も早くなります。
また、始めはたくさんエラーも出してしまうと思います。エラーが起きても原因を調べながら徐々に慣れていきましょう。
