今回は、数え上げは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の既定メンバーなので省略できるというだけで、今回の書き方と実質的には同じものである。
オブジェクトブラウザーで確認すると既定メンバーを示す小さな水玉がついている。