t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

VBA Dictionaryオブジェクトを使って配列の要素の合計数を集計する。

今回は、数え上げはDictionaryオブジェクトを使うと楽ですよという話。

やりたいこと

次のような配列がある。

Array("A", "A", "B", "C", "A", "B", "A")

次のように、それぞれの数を集計したい。

A= 4
B= 2
C= 1

コード

上記の要望は、以下のコードで実現できる。

Sub 数え上げ()
    arr = Array("A", "A", "B", "C", "A", "B", "A")
    Dim DIC As Object
    Set DIC = CreateObject("Scripting.Dictionary")
    For Each x In arr
        If DIC.Exists(x) Then
            DIC(x) = DIC(x) + 1
        Else
            DIC.Add x, 1
        End If
    Next
    
    For Each k In DIC.Keys
        Debug.Print k; "="; DIC(k)
    Next
End Sub

ここで利用しているのが、Scripting.Dictionaryオブジェクトだ。
Collectionの強力版のようなもので、キーの存在チェックなどの機能がある。

まず配列をFor Eachでまわし、取得した値("A"など)がキーとして存在するかチェック。(以下、"A"の場合で説明)
無ければ"A"をキー、値を1としてDICに登録する。
在れば、DIC("A")の値に1を加算する。

配列の全値をまわし終えたら、次にDICのキーをFor Eachでまわしながら、Debug.Printでキーと値を出力する。

以上で完了。

なお、Microsoft Scripting Runtimeを参照設定しておくと、DICオブジェクトの生成は次のように1行で済む。

Dim DIC As New Scripting.Dictionary

※2017/02/03 現在では次のように宣言とオブジェクトのSetを分ける方法を推奨しています。

Dim DIC As Dictionary
Set DIC = New Dictionary

【参考】
thom.hateblo.jp


参照設定した方がインテリセンスによってコード入力支援が得られるので、最終的にCreateObjectに直す場合もコーディング時は参照設定しておくと楽だ。

2017/02/03 追記

先ほどこちらの記事で便利な書き方を発見。
chemiphys.hateblo.jp

Dictionaryに値を追加する際はわざわざExistsで調べてAddしなくても、Item(key)に直接代入できるようだ。

Sub 集計サンプル()
    Dim dic As Dictionary: Set dic = New Dictionary
    Dim sampleArray: sampleArray _
        = Split("A A B B B C D D D D")

    Dim c
    For Each c In sampleArray
        dic.Item(c) = dic.Item(c) + 1
    Next
    
    Dim k
    For Each k In dic.Keys
        Debug.Print k & "が" & dic.Item(k) & "個"
    Next
End Sub

実行するとこのように表示される。

Aが2個
Bが3個
Cが1個
Dが4

ちなみに上で紹介した記事ではDictionaryを格納した変数Dbに直接Db(key) = xxという風に代入しているが、あれはItemプロパティがDictionaryの既定メンバーなので省略できるというだけで、今回の書き方と実質的には同じものである。

オブジェクトブラウザーで確認すると既定メンバーを示す小さな水玉がついている。
f:id:t-hom:20170203032042p:plain

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。