[VBA][HowTo][Dictionary]連想配列の使い方

今回はVBAのDictionaryオブジェクトを取り上げてみたいと思います。

VBAを作成中に配列を操作している時次のようなことを思ったことはないでしょうか?

  • キーと値の組み合わせで配列を管理したい。
  • 複数のリストをキーで突合して処理したい。
  • 配列内を検索しながら大量の繰り返し処理が必要になった。

普通の配列だと配列内をループ処理で対象を見つけていくことしか出来ませんが、これから紹介するDictionaryはこれらの問題を解消してくれる手段の一つとして有効かもしれません。

Dictionaryを正しく使いこなして、処理の効率化を目指してください。


Dictionaryについて

VBAで使用できる連想配列オブジェクトです。
キーとデータの組み合わせで配列が構成されているのが特徴です。

  • ユニーク(重複していない)なキーのみ設定可。
  • キーを元に設定した値を抽出が可。
  • 値にはオブジェクトを格納することも可。
  • キーを検索することが可。

その他いろいろ使えます。
普通の配列とうまく使い分けるのがコツです。

ここではDictionaryを使って簡単なコードを紹介します。

CreateObjectを使用する場合

Dim oDic As Object
Set oDic = CreateObject("Scripting.Dictionary")

'>>>> process <<<<<

Set oDic = Nothing

ライブラリファイル使用する場合

あらかじめ参照設定から以下ライブラリを参照してください。
ライブラリ名:Microsoft Scripting Runtime

Dim oDic As Dictionary
Set oDic = New Dictionary

'>>>> process <<<<<

Set oDic = Nothing

どちらの宣言が正しい?

宣言についてはどちらのやり方も問題ありません。ただしWEBで検索するとCreateObjectを使用するパターンの方が多い傾向があります。

次に挙げるメリットとデメリットを踏まえて最適な選択をしていきましょう。

CreateObject使用のメリット

  • コードの使い回しが可。
  • ライブラリの参照設定が不要。
  • エディタ上で自動クイックヒントが表示されない。

ライブラリファイル使用のメリット

  • コードの使い回しが可。
  • ファイル単位で都度ライブラリの参照設定が必要。
  • エディタ上で自動クイックヒントが表示される。

作成したロジックを他で流用することを想定する場合には「CreateObject」で、単一ファイルで完結する開発の場合には「ライブリファイル」を使用するなどの使い分けも良いかと思います。

しかし自動クイックヒントは開発中にオブジェクトのプロパティやメソッドなどの入力補助にとても役立ち、開発速度を高めてくれます。

自動クイックヒント

良いとこ取りを考えるならば、開発中は「ライブラリ」ベースで作成して、完成後に「CreateObject」に置き換える方法です。

Dictionaryのプロパティとメソッド

プロパティ 説明
Count 連想配列に格納された値の数
Item キーに関連付けられた値
Key キー
CompareMode キー比較時に、文字の大小を区別するか否か指定。
vbBinaryCompare(0):区別する。
vbTextCompare(1):区別しない。
メソッド 説明
Add キーに値を関連付けて追加する。
Exsits 指定したキーが存在を確認する。
Items 連想配列の値を配列にして返す。
配列のインデックス番号は0(ゼロ)から
Keys 連想配列のキーを配列にして返す。
配列のインデックス番号は0(ゼロ)から
Remove 指定したキーおよび値を削除
RemoveAll 全てのキーと値を削除

Dictionaryへデータの追加と削除

Sub Sample()
Dim oDic As Dictionary

    Set oDic = New Dictionary
    
    oDic.Add "AAA", 100
    oDic.Add "BBB", 200
    oDic.Add "CCC", 300
    oDic.Add "DDD", 400
    oDic.Add "EEE", 500
    
    MsgBox oDic.Count

    oDic.RemoveAll
    
    Set oDic = Nothing

End Sub

これはDictionaryを宣言後、キーと値を設定しているサンプルです。

最後にDictionaryに格納された件数をメッセージボックス表示させています。

Dictionaryへの追加方法は以下の通りです。

これは自動クイックヒントが表示された様子ですが、追加メソッドである「Add」に必要なパラメータを表示してくれています。

Key:キー
Item:値

   
    oDic.Add "AAA", 100
    oDic.Item("AAA") = 100
    oDic("AAA") = 100

上の追加方法はどのやり方でも追加が可。

Dictionaryへ追加された件数を確認するプロパティは「Count」です。

   
    MsgBox oDic.Count

Dictionaryへ追加したキーおよび値の削除を以下の「RemoveAll」を使用します。

    oDic.RemoveAll

「RemoveAll」は全データを削除します。

個別にキーを指定して削除したい場合には以下のように「Remove」を使用します。

    oDic.Remove "AAA"

「Remove」メソッドでDicrionary内の「AAA」キーおよび関連付けられた値を削除します。

Dictionaryのキー検索

Sub Sample()
Dim oDic As Dictionary

    Set oDic = New Dictionary
    
    oDic.Add "AAA", "ZZZ"
    oDic.Add "BBB", "YYY"
    
    If oDic.Exists("AAA") Then
        MsgBox oDic("AAA")
    End If

    Set oDic = Nothing

End Sub

これはDictionaryへ値を追加後に「AAA」のキーで値が追加されたか確認しています。

    If oDic.Exists("AAA") Then

返り値はBoolean型:True、Falseです。

キーが検索された場合、キー「AAA」に関連付けられた値をメッセージボックスに表示しています。

    MsgBox oDic("AAA")
    MsgBox oDic.Item("AAA")

Dictionaryは上のようにキーをDictionaryオブジェクトへ添えると値を取り出せます。

Dictionaryの繰り返し処理

Sub Sample()
Dim oDic As Dictionary
Dim arrList As Variant
Dim i As Integer
Dim key As Variant

    Set oDic = New Dictionary

    oDic.Add "AAA", "ZZZ"
    oDic.Add "BBB", "YYY"
    oDic.Add "CCC", "XXX"
    oDic.Add "DDD", "WWW"
    oDic.Add "EEE", "VVV"
        
    '>>> Case-01 <<<
        
    For i = 0 To oDic.Count - 1
        Debug.Print oDic.Keys(i)   'Key
        Debug.Print oDic.Items(i)  'Item
    Next
    
    '>>> Case-02 <<<
    
    arrList = oDic.Keys
    
    For i = LBound(arrList) To UBound(arrList)
        Debug.Print arrList(i)       'Key
        Debug.Print oDic(arrList(i)) 'Item
    Next

    '>>> Case-03 <<<

    For Each key In oDic
        Debug.Print key             'Key
        Debug.Print oDic.Item(key)  'Item
    Next
    
    Set oDic = Nothing

End Sub

これはDictionaryへ追加したデータを繰り返し処理で順にイミディエイトウィンドウへ出力している処理です。

Case-01 から Case-03 まで見栄えは異なりますが、どの処理も同じ結果を出力します。

Case-01 はインデックスを使用した値の抽出方法です。Case-01 のやり方でキーを取り出すことも可能です。

    For i = 0 To oDic.Count - 1
        Debug.Print oDic.Keys(i)   'Key
        Debug.Print oDic.Items(i)  'Item
    Next

Case-02 は「Keys」メソッドで変数「arrList 」に連想配列のキーを0から始まる配列を出力します。出力された配列の繰り返し処理でDictionaryのデータを取得しています。

    arrList = oDic.Keys
    For i = LBound(arrList) To UBound(arrList)
        Debug.Print arrList(i)       'Key
        Debug.Print oDic(arrList(i)) 'Item
    Next

Case-03 はコレクションに対する繰り返し処理「For Each」ステートメントを使用した例です。

    For Each key In oDic
        Debug.Print key             'Key
        Debug.Print oDic.Item(key)  'Item
    Next

ただの繰り返し処理というだけなら可読性の観点からCase-01、Case-03 が良いと思います。

Case-02 はキー配列「arrList 」を他の処理でも使用する用途がある場合には良いかもしれませんが、遠回りするような処理よりも簡潔な処理を採用する方が望ましいです。

Dictionaryを使用した重複しないリストの作成

以下の表のリストを読み取り重複しないリストを作成する。

[Sheet:SampleSheet]

Sub Sample()
Dim oDic As Dictionary
Dim arrList As Variant
Dim i As Integer
    
    With Worksheets("SampleSheet")
        arrList = .Range("A1:B" & .Range("B" & .Rows.Count).End(xlUp).Row).Value
    End With
    
    Set oDic = New Dictionary
    
    For i = LBound(arrList) To UBound(arrList)
        If Not oDic.Exists(arrList(i, 1)) Then
            oDic.Add arrList(i, 1), arrList(i, 2)
        Else
            oDic.Item(arrList(i, 1)) = oDic.Item(arrList(i, 1)) + arrList(i, 2)
        End If
    Next
    
    With Worksheets("SampleSheet")
        For i = 0 To oDic.Count - 1
            .Range("D" & i + 1).Value = oDic.Keys(i)
            .Range("E" & i + 1).Value = oDic.Items(i)
        Next
    End With
            
    Set oDic = Nothing

End Sub

これは表のデータを配列に読み込み、その後Dictionaryに格納していく過程で、キー検索して対象キーが存在すれば値を加算する。

キーが存在しなければデータを追加し、Dictionary内で重複しないリストを作成していく。

その後、読み込みシートのD列にキーをE列に合算値を書き出していく処理です。

[Sheet:SampleSheet] 処理結果

Dictionaryはキー検索を使った処理に強みがありますので、用途に合わせて適切に活用していきましょう。