VBA

【VBA】配列が空の状態のバリエーションと空の状態を判定する関数

記事内に商品プロモーションを含む場合があります

配列が空の状態とは】

空の状態の定義として、ここでは配列を宣言したものの、
中身(要素)が入っていない状態のことを指します。

中身(要素)が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文で回すときに、
要素の取り出しは言わずもがなですが、
どちらも配列を扱うときには重要なコードです。

静的配列と空の状態をまとめると以下のようになります。

静的配列は配列としては空ではなく、
空の要素を持った配列という位置づけ

よって、要素数の出力や要素の取り出しでエラーが生じない

静的配列の使用はおすすめしない

一見エラーに強く、取り扱いしやすそうですが、

実務において静的配列の使用はおすすめしません。
私はコードを書くときに一切、静的配列は使用しません

なぜなら、静的配列は最初に宣言した要素数以上の要素を入力することができません。

これは配列として致命的欠陥です。

これでは、とりあえず気軽に配列に要素を入れたり、要素を入れてから数を数えたり、条件に合うものだけを配列に取り込んだりといった行為が難しくなります。

配列とはプログラミングの基本です。
配列を扱うからこそ、思考が整理され、複雑なコードを書かなくても処理ができるようになるはずなのにこれでは本末転倒です。

配列を取り扱うために、コードが複雑化します。
エラーが生じないのは利点ですが、全く実務では使い物になりません。

こちらでも解説しています。

【VBA】配列は動的配列一択である理由と配列宣言の最適解 このページでわかること 動的配列と静的配列の違い 静的配列は実務では使用価値がない理由 配列の宣言と使い方の実務上の最適...

動的配列の場合

動的配列の空の状態

動的配列の空の状態を解説します

動的配列とは

  • 変数宣言時に要素数(配列に入れる要素の数)を指定しないタイプの配列
  • 後から要素数を自由に変更できるのが最大の特徴
    実務ではこれ一択。
  • ただし、取り扱い方次第でエラーが発生し、扱いが難しい

動的配列での宣言時の配列の状態を見ていきます

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の要素を持った配列という状態で、配列は空ではないという扱いです。

一方で、要素数を再宣言しないと要素の追加ができませんし、配列の要素数を常に把握する必要があるなど、それでも不便なのは不便です。

もっと手軽に配列を使うために要素を何も考えずに追加できる関数を作りました。
私が実務でコードを書く際はこの関数を使わないコードはない。というくらい必須で使っています。

【VBA】配列に要素を追加する関数(任意の位置に対応可能) わかること 配列に簡単に要素を追加できる関数のコードとその使い方 こんにちはhokkyokunです。 配列の関数をいくつ...

動的配列と空の状態をまとめると以下のようになります。

動的配列は要素数の再宣言前は
要素数の出力や要素の取り出しでエラーが生じる

扱いとしては、配列が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

重要なのは

  1. エラーを回避できること
  2. 配列として要素を全く持っていない=空という状態を把握できること

これら2つの点について、上記の関数は正確に、かつ効率よく判定できています。

まとめ

いかがでしたでしょうか。
まとめてみます。

まとめ
  • 配列は動的配列と静的配列で初期の状態が異なる
  • 動的配列は配列が空の状態からスタート
  • 静的配列は空の値を持った配列からスタート
    (配列は空ではない)
  • Array関数とEraseで配列を初期化すると挙動が変わる。
    おすすめはArray関数
  • IsEmpty関数は配列が空かどうかを正確に判定してくれない。
  • 作成したオリジナル関数は正確にかつ効率的に判定してくれる

配列を便利に使いやすくする関数を作っています。

最後に、

ココナラでVBA、Pythonの作成代行を行っています。
よければ、↓からご依頼お待ちしております。

プログラミング代行いたします。

Python・VBAのコード対応です。

【VBA】
エクセルの自動処理全般

【Python】
スクレイピングによる、インターネット操作の自動化
デスクトップツール(データ解析等)
ワードプレスの自動化・効率化(自動更新、記事新規作成等の自動化)

ココナラで依頼を受けておりますので、お気軽にご相談ください。

依頼はこちらから

ココナラの会員登録がまだの方↓

無料登録はこちら

また、VBAを学習するなら動画での学習がおすすめです。
世界最大級の学習用動画プラットフォームUdemyにはVBAの動画がたくさんアップロードされています。よければ覗いてみてください。

Udemyの公式サイトはこちらです。

ではでは。