【VBA】可変長配列と便利な用途(文字数のカウント・ExcelのVBA高速化)

VBA

VBAにて、要素数を変えることが出来る可変長配列(動的配列)の解説と、便利な使用例を2つ、ご紹介いたします。

便利な使用例
①ある文字(列)が含まれる数を数える
②Excelのセルへの書きこみの高速化

可変長配列(動的配列)の基本的な使い方

変数の型を指定する場合

'宣言の方法
Dim StrAry() As String

'要素数の決定
ReDim StrAry(3)

'あとは通常の固定長配列と同じように使えます
StrAry(1) = "いぬ"
StrAry(2) = "ねこ"
StrAry(3) = "さる"

MsgBox "2番目は" & StrAry(2)

変数を宣言するときに、通常の固定長配列では「Dim StrAry(3)」のように宣言するところを、「Dim StrAry()」のように、要素数を省略します。
こうすることで、変数「StrAry」は、可変長の配列になります。
このように定義した可変長配列を使うには、「Redim」を使って要素数を指定して、使うことになります。
なお、「Dim StrAry(3)」のように固定長で宣言した場合は、「Redim」を使って後から要素数を変えることは出来ません。

Variant型を使う場合

Variant型の変数は、宣言するときに括弧を付けなくても、配列として使えます。

「変数名() As Variant」のように括弧を付けても使えますが、不要な記述なので、敢えて付ける必要は無いかと思います。

'宣言の方法
Dim VarAry As Variant

'要素数の決定
ReDim VarAry(3)

'あとは上記のString型配列と同じように使えますので省略します

また、Variant型変数には、配列をそのまま格納することが可能です。

'String型配列
Dim StrAry(3) As String
'Variant型変数
Dim VarAry As Variant

'String型配列に値を設定
StrAry(1) = "たぬき"
StrAry(2) = "きつね"
StrAry(3) = "いのしし"

'Variant型変数に配列をそのまま格納
VarAry = StrAry

'Variant型変数を参照
MsgBox "2番目は" & VarAry(2)

配列を扱うための関数

UBound関数:配列の要素数(インデックスの最大値)を返す

構文

UBound(配列変数名 [,次元数])

第1引数に指定した配列変数の要素数(インデックスの最大値)を、Long型で返します。
多次元配列の場合は、第2引数に次元数を指定すると、2次元目以降の要素数も返すことができます。(使用頻度が低いので、詳しい説明は割愛させて頂きます。)

使用例

上記のVariant型変数のサンプルで使った「VarAry」に対して

MsgBox UBound(VarAry)

のようにすると、「3」が返されます。

Split関数:指定の文字で文字列を分割して、配列を返す

構文

Split(文字列, 区切り文字)

当関数で返された配列は、インデックスの初期値が「0」になります。
以下の例をご覧ください。

使用例

'文字列変数
Dim StrSample As String
'配列格納用
Dim ArySample As Variant

'文字列
StrSample = "しりとり,りす,すずめ"
'Split関数で文字列を区切る
ArySample = Split(StrSample, ",")

'配列「ArySample」を参照
MsgBox "0番目は:" & ArySample(0)
MsgBox "1番目は:" & ArySample(1)
MsgBox "2番目は:" & ArySample(2)

以上のようなVariant型変数の性質、および配列を扱う関数を利用した便利な使用例を、ご紹介いたします。

ある文字(列)が含まれる数を数える

例えば、「ちいさな はなが さいている」の中に、「い」が何文字含まれるか数えたいとします。
この場合、Split関数とUBound関数を使うことで、数えることが出来ます。

Dim StrSample As String
Dim ArySample As Variant

'文字列
StrSample = "ちいさな はなが さいている"
'Split関数で文字列を区切る
ArySample = Split(StrSample, "い")

'インデックスの最大値が、文字「い」が含まれる数になる
MsgBox UBound(ArySample)

補足

なぜ、『配列のインデックスの最大値が、文字「い」が含まれる数になるか?』ですが、Split関数で区切られた配列「ArySample」の中を見て頂ければ、わかりやすいかと思います。

'配列「ArySample」の中
Debug.Print "0番目:" & ArySample(0)
Debug.Print "1番目:" & ArySample(1)
Debug.Print "2番目:" & ArySample(2)
Debug.Print "3番目:" & ArySample(3)
'Debug.Print "4番目:" & ArySample(4) '← これは「インデックスが有効範囲にありません」というエラーになる

実行結果

0番目:
1番目:さな はなが さ
2番目:て
3番目:

このように、文字列変数「StrSample」を、文字「い」で区切ったため、「い」で挟まれた間の文字が、順に配列「ArySample」に設定されます。

Split関数の説明で述べた通り、配列のインデックスは「0」で始まります。
文字列「さな はなが さ」の最初に出てくる「い」の前の文字「ち」が、配列の最初(0番目)に入り、最後に出てくる「い」の後ろの文字「る」が、配列の最後(3番目)に入ります。
このため、配列「ArySample」に対してUBound関数を使うと、インデックスの最大値「3」が、「い」が含まれる数と一致します。

なお、以下のように数えたい文字が2文字以上の場合でも、同じ方法で数えることが可能です。

'文字列
StrSample = "北千住南千住三河島"
'Split関数で文字列を区切る
ArySample = Split(StrSample, "千住")

'インデックスの最大値が、文字列「千住」が含まれる数になる
MsgBox UBound(ArySample)

セルへの書きこみの高速化

次に、VBAの高速化テクニックについてご紹介します。
これは、「Variant型変数に、配列をそのまま格納できる」という性質を使います。

以下の記事で扱ったFizzBuss問題を、高速化してみます。

【Excel VBA】途中経過の表示方法(StatusBar)

FizzBuzz問題とは?

1から順に数を数えていき、以下のように発言していくゲームです。
・3の倍数なら「Fizz」
・5の倍数なら「Buzz」
・両方の倍数(すなわち15の倍数)なら「Fizz Buzz」
・いずれでもなければその数を言う
元々は海外の言葉遊びで、そのルールをプログラムに実装したものです。

ここで使うテクニックは、以下の通りです。

  1. ワークシートのセル範囲をVariant型変数に代入する事で、2次元配列が作成される。
    1次元目が行番号、2次元目が列番号の配列が作成されますので、変数名(行番号,列番号)」と指定すれば、「Cells(行番号,列番号)」と同じようなイメージで配列を編集できます。
  2. 2次元配列を編集する。
  3. 2次元配列の編集終了後、配列をワークシートのセル範囲にまとめて代入する。

具体的な方法は、以下の通りです。

Dim Idx1 As Long

'配列を定義
Dim ArySample As Variant

'-----------------------------------------------
'ワークシートのセル範囲をVariant型変数に代入する
'-----------------------------------------------
ArySample = Sheets("Sheet1").Range("A1:B100000")

'-----------------------------------------------
'FizzBuss問題(配列を編集する)
'-----------------------------------------------
For Idx1 = 1 To 100000
    'A列:数字を表示
    ArySample(Idx1, 1) = Idx1
    
    'B列:FizzBussの答えを表示
    If Idx1 Mod 3 = 0 And Idx1 Mod 5 = 0 Then
        ArySample(Idx1, 2) = "Fizz Buzz"
    ElseIf Idx1 Mod 3 = 0 Then
        ArySample(Idx1, 2) = "Fizz"
    ElseIf Idx1 Mod 5 = 0 Then
        ArySample(Idx1, 2) = "Buzz"
    Else
        ArySample(Idx1, 2) = Idx1
    End If
    
Next

'-----------------------------------------------
'配列をワークシートのセル範囲にまとめて代入する
'-----------------------------------------------
Sheets("Sheet1").Range("A1:B100000") = ArySample

結果は歴然です。
私の手元のパソコンで試してみたところ、「Cells(Idx1, 2) = xxx」のように普通に処理すると32秒かかっていたのが、上記の方法を使うと1秒かからずに終了しました。

なお、配列は必ず2次元で作成されます。
そのため、以下のようにA列のみをVariant型変数に代入しても、2次元配列になります。

Dim ArySample As Variant
'A列のみを代入する
ArySample = Sheets("Sheet1").Range("A1:A100000")

'変数「ArySample」は2次元配列になるので、
'以下のように2次元目のインデックスも指定する必要があります
ArySample(Idx1, 1) = "Fizz Buzz"

まとめ

ここでは、可変長配列(動的配列)の基本的な使い方と、便利な用途を紹介しました。
Variant型の変数は、配列として使うことができます。この性質を使って、以下のようなことができます。

①ある文字(列)が含まれる数を数える
②Excelのセルへの書きこみの高速化

コメント

タイトルとURLをコピーしました