要素数が0個の配列、いわゆる空の配列は、
Array() と引数を省略したArray関数で作ることができます。
この空の配列は意外と便利な仕様が盛りだくさんで、
汎用関数の作成時に活用することができます。
今回はこの「空の配列」について解説します。
空の配列の生成方法
空の配列を作成するのは簡単で、
Dim Arr Arr = Array()
このようにArray関数の引数を省略すると生成できます。
人工ではなく自然界(?)に存在する空の配列としては、
引数の数を動的にする機能「ParamArray」使用時に、
Sub 引数の数を自由に渡せる関数(ParamArray 引数()) Dim 各引数 For Each 各引数 In 引数 ' 各引数への処理 Next End Sub Sub 空の配列が渡る例 Call 引数の数を自由に渡せる関数(1, 2, 3) ' Array(1,2,3)が渡る Call 引数の数を自由に渡せる関数(1) ' Array(1)が渡る Call 引数の数を自由に渡せる関数() ' 空の配列が渡る End Sub
このように「ひとつも引数に渡さない(ParamArray自体を省略)」した際に、
ParamArray配列に空の配列が渡ることで生成されます。
今回のお話は、
「この空の配列が汎用関数に便利だからArray()で人工生成しよう!」
というお話になります。
空の配列の仕様
この空の配列ですが、まずは空と言っても配列は配列なので、
配列変数への代入でエラーにならず、IsArrayもTrueになります。
このため配列を受け取る各種関数に渡しやすいというのが第一のメリットですね。
その上で重要になる第二のメリットが、
Uboundが-1、Lboundが0になるという仕様です。
この仕様はなかなかに便利な仕様で、まずは「要素数の計算」
UBound(配列) - LBound(配列) + 1
この結果が「0」になってくれるため、
要素0の配列であることが直感的にわかります。
要素数を求める汎用関数を作っている際も、
ノーエラーで「0」を返してくれるという優れた仕様ですね。
Debug.Print Count配列の要素数(Array()) ' = 0 ' 配列要素数の取得 Function Count配列の要素数(Arr, Optional 次元 = 1) As Long Count配列の要素数 = UBound(Arr, 次元) - LBound(Arr, 次元) + 1 End Function
そしてUboundが-1、Lboundが0になるという仕様のさらなるメリットとして、
この仕様はFor文の仕様にもよくマッチしています。
例えばParamArrayが空の配列となった場合、
以下のFor文は「For 0 To -1」となり一度も実行されません。
Sub 引数の数を自由に渡せる関数(ParamArray 引数()) Dim i As Long For i = LBound(引数) To UBound(引数) Next End Sub
つまりエラー処理をしなくてもForループをスキップしてくれるということです。
PramArray省略時の動きを制御する上で、これは相当ありがたい仕様です。
そして最後に第三のメリットとして、このFor文と同じように、
For Each ステートメントもエラーなしで通過される仕様です。
Sub 引数の数を自由に渡せる関数(ParamArray 引数()) Dim 各引数 For Each 各引数 In 引数 Next End Sub
このFor Each文もParamArray省略時はエラーなしでスキップしてくれます。
以上三つのメリット
- 配列変数に代入でき、IsArrayもTrue
- Uboundが-1のため要素数が0でForループをスキップ可
- For Eachのループもノーエラーでスキップされる
これが配列を扱う関数やコードととても相性がよく、
エラー処理の工数を大きく減らしてくれます。
空の配列を汎用関数の戻り値にする
さてこの便利な空の配列をいつ使うか(作るか)ですが、
配列を返す自作関数の返り値として使うのが便利です。
例えば、
Function 配列を返す自作関数() As Variant ' 配列を生成するコード Dim 生成配列 配列を返す自作関数 = 生成配列 End Function
このような自作関数において、場合によっては配列が生成できないこともあります。
例えば「条件に合致するデータをリスト化する関数」において、
条件に合致するデータがひとつもなかった時などですね。
このとき、Functionの返り値をVarinatの初期値「Empty」にしていると、
呼出元でUboundやForEachを書いていた場合にエラーになってしまいます。
そのせいで呼び出し元で「IsEmpty」を判定するようだと、
せっかくの汎用関数の良さが台無しになってしまいますね。
そこで前述の3つのメリットを活用し、
「配列が生成できない場合は空配列を返す」関数にしてみましょう。
Function 配列を返す自作関数() As Variant Dim 生成配列() ' ここで配列を生成 If 生成がうまく行った場合 Then 配列を返す自作関数 = 生成配列 Else 配列を返す自作関数 = Array() End If End Function
こうしておくことで、例えば
Dim Arr対象商品 Arr対象商品 = 配列を返す自作関数(対象シート) For Each 商品 In Arr対象商品 ' 商品ごとの処理 Next
こんなコードを書いたとき、
対象商品がなければForEachをスキップしてくれるようになります。
もちろんノーエラーというのはいいことだけではなく、
エラーが出ない分、より気を付けなければいけないこともあります。
ただ、それをわかった上で使う分には、
エラー処理の工数を格段に減らしてくれるテクニックになります。
「配列を返す関数が必ず配列を返してくれる」だけでも素晴らしいメリットなので、
ぜひとも汎用関数の返り値に活用してみてください。
空の配列の判定方法
最後に空の配列の判定方法を解説します。
主に
- IsMissing関数で判定(空の配列だとTrue)
- UBound関数の結果が-1
- 要素数(UBound - LBound +1)が0
この3つの方法を用います。
2番目と3番目は同じことを言っていますが、おすすめは3番目の方法です。
もちろんわざわざ(UBound - LBound +1)を計算するという意味ではなく、
自作の要素数カウント関数を使うということですね。
' 空の配列か判定 If Count配列の要素数(配列) = 0 Then
' 配列要素数の取得 Function Count配列の要素数(Arr, Optional 次元 = 1) As Long Count配列の要素数 = UBound(Arr, 次元) - LBound(Arr, 次元) + 1 End Function
このコードを見てわかる通り、
「もし要素数が0だったら」
という非常に読みやすくわかりやすいコードになりますね。
ただし、この方法は前述のParamArrayには使えません。
ParamArrayは厳密には通常の配列とは異なるため、
配列を受け取る汎用関数にParamArrayを渡すことはできません。
※ 一旦Variant変数に入れてから渡す必要があります。
ParamArrayが省略されたかを調べたい場合は、
それ専用の関数であるIsMissing関数を使用してください。
以上で空の配列Array()の解説を終わります。
知っておくとかゆいところに手が届くライブラリを作れますので、
汎用関数づくりにお役立てください。