- VBAの配列が空の状態になる、そのバリエーションを解説
- 動的配列で宣言すると配列が空という扱い。
エラーになる - 静的配列だと空の要素をもつ配列という扱い。
配列は空ではない。
- 動的配列で宣言すると配列が空という扱い。
- Array関数やEraseで配列を空にできるが、その後の扱いには注意が必要。
- IsEmpty関数はあまり役に立たない、正確に配列の状態を判定してくれない。
- 実務に耐えられるエラー関数を作ったので紹介。
これを使うと配列が圧倒的に使いやすくなります。
【配列が空の状態とは】
空の状態の定義として、ここでは配列を宣言したものの、
中身(要素)が入っていない状態のことを指します。
中身(要素)がEmptyという空の値が入っている配列は空ではないという扱いとします。
動的配列と静的配列で性質が異なり、これが配列の扱いを難しくする一つの要因となります。
プログラミング代行いたします。
Python・VBAのコード対応です。
【VBA】
エクセルの自動処理全般
【Python】
スクレイピングによる、インターネット操作の自動化
デスクトップツール(データ解析等)
ワードプレスの自動化・効率化(自動更新、記事新規作成等の自動化)
ココナラで依頼を受けておりますので、お気軽にご相談ください。
ココナラの会員登録がまだの方↓
VBAを学習するには、動画プラットフォームUdemyがおすすめです。
Udemyの公式サイトはこちらです。
静的配列の場合
静的配列の空の状態
まず静的配列の空の状態を解説します。
まず静的配列での配列が空の状態を見ていきます。
Sub testArray1()
'要素数が1(宣言としては0となる)の静的配列
Dim arrs(0) As Variant
'IsEmpty関数では配列はFalse=Emptyではない
Debug.Print IsEmpty(arrs)
'以下が出力
'===============================
'False
'===============================
'ただし、中身は空です。
Debug.Print IsEmpty(arrs(0))
'以下が出力
'===============================
'True
'===============================
'要素数を取り出してもエラーにならない
Debug.Print UBound(arrs)
'以下が出力
'===============================
'0
'===============================
'要素の取り出しも同様
Debug.Print arrs(0)
'何もない状態が出力される
'===============================
'
'===============================
End Sub
先に要素数を宣言している静的配列では
配列は空ではありません。
要素をまだ入力していないので、Emptyという値が入った配列という扱いです。
そしてこれが重要なのですが、
配列の要素数の出力や要素を取り出す作業を行ってもエラーはでません。
要素数は配列をFor文で回すときに、
要素の取り出しは言わずもがなですが、
どちらも配列を扱うときには重要なコードです。
静的配列と空の状態をまとめると以下のようになります。
静的配列は配列としては空ではなく、
空の要素を持った配列という位置づけ
よって、要素数の出力や要素の取り出しでエラーが生じない
静的配列の使用はおすすめしない
一見エラーに強く、取り扱いしやすそうですが、
なぜなら、静的配列は最初に宣言した要素数以上の要素を入力することができません。
これは配列として致命的欠陥です。
これでは、とりあえず気軽に配列に要素を入れたり、要素を入れてから数を数えたり、条件に合うものだけを配列に取り込んだりといった行為が難しくなります。
配列とはプログラミングの基本です。
配列を扱うからこそ、思考が整理され、複雑なコードを書かなくても処理ができるようになるはずなのにこれでは本末転倒です。
配列を取り扱うために、コードが複雑化します。
エラーが生じないのは利点ですが、全く実務では使い物になりません。
こちらでも解説しています。
動的配列の場合
動的配列の空の状態
動的配列の空の状態を解説します
動的配列での宣言時の配列の状態を見ていきます
Sub testArray2()
'動的配列で宣言し、何も入れない場合
Dim arrs As Variant
'↑宣言はDim arrs() As Variantのように()をつけるとエラー番号が(9番)になる
'エラーが出ます(13番)
Debug.Print UBound(arrs)
'エラーが出ます(13番)
Debug.Print arrs(0)
'配列は空(Empty)という扱い
Debug.Print IsEmpty(arrs)
'以下が出力
'===============================
'True
'===============================
'要素を追加(追加し放題!!)
ReDim arrs(0)
Debug.Print UBound(arrs)
'以下が出力
'===============================
'0
'===============================
'配列は空(Empty)ではないという扱い
Debug.Print IsEmpty(arrs)
'以下が出力
'===============================
'False
'===============================
Debug.Print arrs(0)
'出力しても何も表示されません
'Emptyという値を持った配列という扱い
'いくらでも要素追加し放題(ただし、いちいち宣言が必要…)
ReDim Preserve arrs(1)
End Sub
動的配列はいくらでも要素数を変更し、要素を追加し放題なのですが、
宣言して何も処理しないまま要素数の出力や要素の取り出しを行うとエラーが発生します。
状態としては配列が空(Empty)の状態です。
ただし、一度要素数を宣言すればその後はエラーが発生しません。
このとき(要素をまだ入力していない場合)、Emptyの要素を持った配列という状態で、配列は空ではないという扱いです。
一方で、要素数を再宣言しないと要素の追加ができませんし、配列の要素数を常に把握する必要があるなど、それでも不便なのは不便です。
もっと手軽に配列を使うために要素を何も考えずに追加できる関数を作りました。
私が実務でコードを書く際はこの関数を使わないコードはない。というくらい必須で使っています。
動的配列と空の状態をまとめると以下のようになります。
動的配列は要素数の再宣言前は
要素数の出力や要素の取り出しでエラーが生じる
扱いとしては、配列がEmptyという状態
宣言時に()をつけても同様
(配列という扱いにはなるが要素数の出力などでエラー)
要素数の再宣言で
Emptyという値を持った配列という扱いになる。
動的配列は要素が追加し放題なので、実務はこちら一択
Array関数を使うとまた様子が変わる
ここでArray関数を使ってみます。
Array関数を使うと配列に効率的に要素を追加できるのですが、
例として以下のコードを書いてみました。
Sub testArray3()
Dim arrs As Variant
arrs = Array("リンゴ", "バナナ", "パイナップル")
Debug.Print "=============================="
Dim arr As Variant
For Each arr In arrs
Debug.Print arr
Next
Debug.Print "=============================="
'以下のように出力
'==============================
'リンゴ
'バナナ
'パイナップル
'==============================
End Sub
このArray関数ですが、
要素を何も入れていないArray関数を配列に充ててやると、状況がまた変わります。
Sub testArray4()
'空のarray()関数をあてた場合
Dim arrs As Variant
'↑宣言はDim arrs() As Variantのように()をつけても同じ
arrs = Array()
'要素数は-1
Debug.Print UBound(arrs)
'以下が出力
'===============================
'-1
'===============================
'要素を指定して取り出そうとするとエラー(9番)
Debug.Print arrs(0)
'↑エラーがでます。
End Sub
空のArray関数を充てると要素数は「-1」という扱いになり、
要素を取り出そうとするとエラーが発生します。
この空のArray関数を充てる作業ですが、
意外に重要な作業です。
なぜなら、配列内の要素を一度リセットするのに使用できるからです。
Array関数は効率的に要素を入力できる
空のArray関数を充てると
要素数は「-1」
要素の取り出しはエラーとなる
空のArray関数を充てると配列の要素を全部クリアできる
Array関数とErase
上記で空のArray関数を充てることで配列の要素をクリアできると説明しましたが、Eraseでも配列の初期化ができます。
個人的にはArray関数でクリアすることをお勧めします。
が、Eraseのほうが好みであればそちらでも大丈夫です。
Sub testArray5()
'Array関数でリセットしてもその後、要素取り出しでエラーは起きない
Dim arrs As Variant
arrs = Array("リンゴ", "バナナ", "パイナップル")
arrs = Array()
Debug.Print "=============================="
Dim arr As Variant
For Each arr In arrs
Debug.Print arr
Next
Debug.Print "=============================="
'以下のように出力=要素が一つもない
'==============================
'==============================
'Eraseだと配列が空(Empty)となるのでエラーが生じる
Dim arrs2 As Variant
arrs2 = Array("リンゴ", "バナナ", "パイナップル")
Erase arrs2
'エラーが発生(92番)
Debug.Print "=============================="
For Each arr In arrs2
Debug.Print arr
Next
Debug.Print "=============================="
End Sub
私が個人的にArray関数のほうを使うのは、そのほうがエラーになる確率が低くなるからです。
ただ、今回の場合は、目的が要素のクリアなので、Array関数でもEraseでも、どちらでも目的は達成しています。
プログラムを作る際にエラーは敵ではないのです(自分が想定していない動きになったとき止まってくれる)が、今回の場合、エラー回避のプログラムを仕込むくらいなら、はじめからエラーの起きないArray関数を私なら使います。
IsEmptyは使えそうで使えない
IsEmpty関数を使うと配列が空(Empty)であるかどうかをチェックできそうですが、詳しくみるとこれだけで判断すると誤る場合があります。
Sub testArray6()
'IsEmpty関数を使用
Dim arrs As Variant
Debug.Print IsEmpty(arrs)
'Variant型の何かがEmptyという扱い
'===============================
'True
'===============================
Dim arrs2() As Variant
Debug.Print IsEmpty(arrs2)
'配列としては宣言されているのでEmptyではない
'===============================
'False
'===============================
ReDim arrs2(0) As Variant
Debug.Print IsEmpty(arrs2(0))
'中身はEmpty
'===============================
'True
'===============================
Dim arrs3 As Variant
ReDim arrs3(0)
Debug.Print IsEmpty(arrs3(0))
'()をつけない場合も同様
'===============================
'True
'===============================
Erase arrs3
Debug.Print IsEmpty(arrs3)
'これはEmptyではないらしい…
'===============================
'False
'===============================
arrs2 = Array()
Debug.Print IsEmpty(arrs2)
'これもEmptyではない
'===============================
'False
'===============================
End Sub
ここで注目していただきたいのは()をつけるかつけないかで挙動が変わる点です。
また、一度要素を入れた配列を空のArray関数やEraseで消した場合はEmptyではない、という扱いです。
IsEmpty関数で配列が空かどうかを判断すると、見誤る可能性がるので全くおすすめしません。
コード | IsEmpty関数の 戻り値 |
実際の状態(返ってきてほしい値) |
()をつけないで、変数宣言 | True | 空(True) |
()をつけて、変数宣言 | False | 空(True) |
Array関数で初期化 | False | 空(True) |
Eraseで初期化 | False | 空(True) |
空の判定はどうするべきか(作成した関数)
では、空の判定とはどうするべきでしょうか。
私は配列が空かどうかを以下の作成した関数でチェックしています。
Function isEmptyArray(ByVal arrs As Variant)
Dim a As Variant
'要素をとり出してエラーが出るかどうか
On Error GoTo err
a = arrs(0)
'エラーが生じたときエラー番号で9か13の場合はFalse
err:
If err.Number = 9 Or err.Number = 13 Then
isEmptyArray = True
Else
isEmptyArray = False
End If
End Function
このプログラムを使って様々なシチュエーションを判定してみます。
Sub testArray7()
'動的配列で空か判定
Dim arrs As Variant
Debug.Print isEmptyArray(arrs)
'True
'()をつけても同様
Dim arrs2() As Variant
Debug.Print isEmptyArray(arrs2)
'True
'静的配列でも使える→静的配列は空の値を持っている配列という扱い
Dim arrs3(0) As Variant
Debug.Print isEmptyArray(arrs3)
'False
'動的配列を再宣言すると配列は空ではなくなる→空の値を持っている配列という扱い
Dim arrs4 As Variant
ReDim arrs4(0)
Debug.Print isEmptyArray(arrs4)
'False
'Array関数でクリアすると実質空の扱い。ちゃんと判定できる
Dim arrs5 As Variant
arrs5 = Array("リンゴ", "バナナ")
'↓当たり前だがこれは空ではないのでFalse
Debug.Print isEmptyArray(arrs5)
'False
'Array関数で空にするとTrue
arrs5 = Array()
Debug.Print isEmptyArray(arrs5)
'True
'Eraseで空にする
Dim arrs6 As Variant
arrs6 = Array("リンゴ", "バナナ")
Erase arrs6
Debug.Print isEmptyArray(arrs6)
'True
End Sub
重要なのは
- エラーを回避できること
- 配列として要素を全く持っていない=空という状態を把握できること
これら2つの点について、上記の関数は正確に、かつ効率よく判定できています。
まとめ
いかがでしたでしょうか。
まとめてみます。
- 配列は動的配列と静的配列で初期の状態が異なる
- 動的配列は配列が空の状態からスタート
- 静的配列は空の値を持った配列からスタート
(配列は空ではない) - Array関数とEraseで配列を初期化すると挙動が変わる。
おすすめはArray関数 - IsEmpty関数は配列が空かどうかを正確に判定してくれない。
- 作成したオリジナル関数は正確にかつ効率的に判定してくれる
配列を便利に使いやすくする関数を作っています。
最後に、
ココナラでVBA、Pythonの作成代行を行っています。
よければ、↓からご依頼お待ちしております。
プログラミング代行いたします。
Python・VBAのコード対応です。
【VBA】
エクセルの自動処理全般
【Python】
スクレイピングによる、インターネット操作の自動化
デスクトップツール(データ解析等)
ワードプレスの自動化・効率化(自動更新、記事新規作成等の自動化)
ココナラで依頼を受けておりますので、お気軽にご相談ください。
ココナラの会員登録がまだの方↓
また、VBAを学習するなら動画での学習がおすすめです。
世界最大級の学習用動画プラットフォームUdemyにはVBAの動画がたくさんアップロードされています。よければ覗いてみてください。
ではでは。