和風スパゲティのレシピ

日本語でコーディングするExcelVBA

Collectionに要素が存在するかチェックする

Collection内に要素が存在するかチェックする方法を解説します。

これを行う標準機能は用意されていませんので、
愚直にFor Each文で一致する要素があるかを判定します。

はじめに~Dictionaryオブジェクトについて

Collectionと似た仕組みで、Dictionary(連想配列)というものがあります。

このDictionaryには「Existsメソッド」がありますので、
Collectionとは異なり要素の存在チェックが一発で終わります。


また、Dictionaryには「一次元配列(Array)に変換する」という、
これもCollectionにはない便利な機能を有しています。


Dictionaryは「KeyとItemをペアで持つ仕組み」なのですが、
Itemを無視してKeyだけで運用すればCollectionとしても使えます。


もし今回のコードを実装したいマクロをまだ作り始めたくらいなら、
今からCollectionの存在チェックを頑張るよりも、
CollectionをDictionaryに置き換える方が実装が簡単でメンテナンスも楽です。


まずはそのことを念頭に置いて、以下の記事をお読みいただくか、
本記事をこのまま読み進めるかをお選びいただければと思います。

CollectionのItemにある値が存在するかチェック

CollectionのItemにある値が存在するかチェックには、
以下のコードを実行します。

Sub コレクション内の要素存在チェックサンプル()

    Dim コレクション As New Collection
    コレクション.Add "みかん"
    コレクション.Add "りんご"
    コレクション.Add "いちご"
    コレクション.Add "さくらんぼ"
    
    ' コレクション内に「みかん」があるかを確認
    Dim is存在判定 As Boolean: is存在判定 = False
    Dim 要素
    For Each 要素 In コレクション
    
        If 要素 = "みかん" Then
            is存在判定 = True
            Exit For
        End If
    
    Next
    
    If is存在判定 Then
        MsgBox "みかんは存在します。"
    Else
        MsgBox "みかんは存在しません。"
    End If

End Sub

For Each文でコレクション内をすべてループし、
一致する値があるかを判定しているストレートなコードです。


このコードに特に注意点はありませんが、
CollectionはFor文でループすると遅くなる点はご注意ください。

Collectionの全件ループには上記のようにFor Each文を使いましょう。

詳しくはこちらをどうぞ。

汎用関数化

上記ForEach文を存在判定のたびに書くのは大変なので、
この判定を何度も行う場合は汎用関数化しておきましょう。

Sub コレクション内の要素存在チェックの汎用関数使用サンプル()

    Dim コレクション As New Collection
    コレクション.Add "みかん"
    コレクション.Add "りんご"
    コレクション.Add "いちご"
    コレクション.Add "さくらんぼ"
    
    ' コレクション内に「みかん」があるかを確認
    If IsCollection内に要素が存在(コレクション, "みかん") Then
        MsgBox "みかんは存在します。"
    Else
        MsgBox "みかんは存在しません。"
    End If

End Sub

' Collectionの要素存在チェック関数
Function IsCollection内に要素が存在(コレクション As Collection, 判定値 As Variant) As Boolean

    Dim 要素
    For Each 要素 In コレクション
    
        If 要素 = 判定値 Then
            IsCollection内に要素が存在 = True
            Exit Function
        End If
    
    Next
    
End Function

使用例を見てわかる通り非常にわかりやすいコードになります。

Collectionをよく使用する方はこの汎用関数を持っておきましょう。


ただし、繰り返しになりますが、これはDictionaryなら一発で終わる話です。

' ディクショナリに「みかん」があるかを確認
If ディクショナリ.Exists("みかん") Then

この汎用関数を用意しておくのは便利ですが、
そもそもDictionaryが使えるならその方がよい点は留意してください。

Collectionにあるオブジェクトが存在するかチェック

Collectionにはオブジェクトも格納できるため、
その場合はFor Each文を以下の通り書き換えます。

Sub コレクション内のオブジェクト要素存在チェックサンプル()

    Dim コレクション As New Collection
    コレクション.Add Worksheets("みかん")
    コレクション.Add Worksheets("りんご")
    コレクション.Add Worksheets("いちご")
    コレクション.Add Worksheets("さくらんぼ")
    
    ' コレクション内に「みかん」名のシートがあるかを確認
    Dim is存在判定 As Boolean: is存在判定 = False
    Dim 要素
    For Each 要素 In コレクション
    
        If 要素 Is Worksheets("みかん") Then ' ←「=」を「Is」に変える
            is存在判定 = True
            Exit For
        End If
    
    Next
    
    If is存在判定 Then
        MsgBox "みかんシートは存在します。"
    Else
        MsgBox "みかんシートは存在しません。"
    End If

End Sub

オブジェクトは判定が「Is」ですのでご注意ください。

CollectionにRangeオブジェクトが存在するかチェック

オブジェクトは「Is」で判定ができるとしましたが、
RangeオブジェクトだけはIs演算子では判定できません。

この場合は「ブック・シートも含めたセルアドレス」が等しいかで判定してください。

Sub コレクション内のRangeオブジェクト要素存在チェックサンプル()

    Dim コレクション As New Collection
    コレクション.Add Range("A1")
    コレクション.Add Range("B1")
    コレクション.Add Range("C1")
    コレクション.Add Range("D1")
    
    ' コレクション内にA1セルがあるかを確認
    Dim is存在判定 As Boolean: is存在判定 = False
    Dim 要素
    For Each 要素 In コレクション
    
        ' ブック名とシート名も含めたセルアドレス「Address(External:=True)」で判定
        If 要素.Address(External:=True) = Range("A1").Address(External:=True) Then
            is存在判定 = True
            Exit For
        End If
    
    Next
    
    If is存在判定 Then
        MsgBox "A1セルは存在します。"
    Else
        MsgBox "A1セルは存在しません。"
    End If

End Sub

 
なお、RangeオブジェクトをCollectionに格納できるということは、
裏を返せば.Valueを省略するとセルそのものが格納されてしまいます。

セル値をCollectionに入れたい場合は、必ず.Valueを明記して下さい。

Collectionの要素存在チェックを行う汎用関数

先ほど「ある値が存在するか」を判定する汎用関数を作りましたが、
これに「オブジェクト・セル」の判定も入れた万能関数がこちらになります。

' Collectionの要素存在チェック関数
Function IsCollection内に要素が存在(コレクション As Collection, 判定要素 As Variant) As Boolean
    Dim 要素
    
    ' ◇ セル
    If TypeName(判定要素) = "Range" Then
    
        For Each 要素 In コレクション
        
            If TypeName(要素) = "Range" Then
                If 要素.Address(External:=True) _
                = 判定要素.Address(External:=True) Then
                    IsCollection内に要素が存在 = True
                    Exit Function
                End If
            End If
            
        Next
    
    ' ◇ セル以外のオブジェクト
    ElseIf IsObject(判定要素) Then
    
        For Each 要素 In コレクション
        
            If 要素 Is 判定要素 Then
                IsCollection内に要素が存在 = True
                Exit Function
            End If
        
        Next
    
    ' ◇ 値
    Else
    
        For Each 要素 In コレクション
        
            If 要素 = 判定要素 Then
                IsCollection内に要素が存在 = True
                Exit Function
            End If
        
        Next
        
    End If
    
End Function
' これらすべて同じ関数で動く
If IsCollection内に要素が存在(コレクション, "みかん") Then
If IsCollection内に要素が存在(コレクション, Worksheets("みかん")) Then
If IsCollection内に要素が存在(コレクション, Range("A1")) Then

 
単に引数の種類に応じて回すForEach文を分けているだけですね。


IsObject関数やTypeName関数を用いれば汎用関数を万能化できます。

実装が簡単な割に効果が大きいので活用してみて下さい。

CollectionにあるKeyが存在するかチェック

CollectionにはItemだけでなくKeyもセットで渡すことができます。

' コレクションに商品名と商品コードをセットで搭載
Dim コレクション As New Collection
コレクション.Add "みかん", "A001"
コレクション.Add "りんご", "A002"
コレクション.Add "いちご", "A003"
コレクション.Add "さくらんぼ", "A004"

このとき、「みかん」が存在するかではなく、
「A001」をKeyとするItemが存在するかを判定する方法を解説します。


ただし、KeyとItemをセットで登録するのであれば、
それこそこれはDictionaryの役割です。

Keyを省略できるというのが唯一のCollectionのメリットであるため、
Key-Itemの登録にCollectionを用いる意味はありません。


以降のコードは
「Dictionaryが使えないMacユーザーがCollectionをDictionaryの代わりに使う」
ためのコードだと思ってください。

Windowsユーザーはこちらの記事をどうぞ。


Sub コレクション内のKey存在チェックサンプル()

    ' コレクションに商品名と商品コードをセットで搭載
    Dim コレクション As New Collection
    コレクション.Add "みかん", "A001"
    コレクション.Add "りんご", "A002"
    コレクション.Add "いちご", "A003"
    コレクション.Add "さくらんぼ", "A004"
    
    ' コレクション内にKey「A001」があるかを確認
    On Error Resume Next
    Dim is存在判定 As Boolean
    Dim x: x = コレクション("A001")
    is存在判定 = (Err.Number = 0)
    On Error GoTo 0
    
    If is存在判定 Then
        MsgBox "A001は存在します。"
    Else
        MsgBox "A001は存在しません。"
    End If

End Sub

 
Collection内に特定のKeyが存在するかチェックする場合は、
コレクション.Item(判定Key)がエラーになるかを調べます。

汎用関数にしたい場合はこちらをご利用ください。

' CollectionのKey存在チェック
Function IsCollectionに指定Keyが登録済(コレクション As Collection, 判定Key As Variant) As Boolean
    On Error Resume Next
    
    Dim is存在判定 As Boolean
    Dim x: x = コレクション(判定Key)
    IsCollectionに指定Keyが登録済 = (Err.Number = 0)
    
    On Error GoTo 0
End Function