知らずに落ちると抜け出せなくなるVBAの落とし穴です。
- Dictionary内の配列に代入した値が反映されない
- Dictionary×配列によるクロス集計の結果が0になってしまう
あたりにお悩みの方は、この落とし穴に落ちていないかご確認ください。
DictionaryのItemに入れた配列(Array)の書き換え
DictionaryのItemに配列を入れてみましょう。
Dim 辞書 As New Dictionary Dim 配列(1 To 3) As Long 辞書.Add "みかん", 配列 辞書.Add "りんご", 配列 辞書.Add "いちご", 配列
上記のコードにより作成したDictionaryは、
| みかん | 0 | 0 | 0 |
|---|---|---|---|
| りんご | 0 | 0 | 0 |
| いちご | 0 | 0 | 0 |
このような2次元配列を作ったイメージになります。
さてここで、keyをみかんとする配列の第1要素を書き換えてみます。
辞書("みかん")(1) = 5 Debug.Print 辞書("みかん")(1)
コードを見る限りは「5」が表示されるようにしか見えないコードですが、
こちらの結果は残念ながら「0」となってしまいます。
DictionaryのItemプロパティはByValのような仕様になっているため、
上記の通り、直接中の配列を書き換えることができません。
辞書("みかん")(1) = 5
このコードは、
- Itemプロパティにより複製された配列の第1要素に5を代入
- この配列はどこにも保存されないためその場で破棄
という手順で処理されるコードになってしまっています。
特にDictionaryを用いてクロス集計を行おうとする際、
例えば「1列目が件数、2列目が個数、3列目が売上」の配列と定義し、

こんな表を、
辞書(Cells(r, 1).Value)(1) = 辞書(Cells(r, 1).Value)(1) + 1 辞書(Cells(r, 1).Value)(2) = 辞書(Cells(r, 1).Value)(2) + Cells(r, 2).Value 辞書(Cells(r, 1).Value)(3) = 辞書(Cells(r, 1).Value)(3) + Cells(r, 3).Value
こんなコードで計算していこうとした際に陥りがちな罠です。
配列 In Dictionaryでは、
よくある「変数=変数 + 値」の計算が出来ませんのでご注意ください。
解決策
この問題の解決方法は大きく分けて以下の2つになります。
配列を一旦変数に取り出し、書き替えてから配列ごと戻す
Dicitonary内に配列を入れる仕様のまま実装する場合は、
一旦配列を外に出し、それを書き換えて配列ごと代入しなおします。
Dim Arr Arr = 辞書("みかん") Arr(1) = 5 辞書("みかん") = Arr Debug.Print 辞書("みかん")(1)
第1要素を 0 ⇒ 5 に書き換えるだけでこのコードになるのでちょっと大変ですね。
クロス集計コードを例にとると、
Dim Arr Arr = 辞書("みかん") Arr(1) = Arr(1) + 1 Arr(2) = Arr(2) + Cells(r, 2).Value Arr(3) = Arr(3) + Cells(r, 3).Value 辞書("みかん") = Arr
このように配列内を書き換えて、終わったら戻すといったコードになります。
Dictionary内に配列を入れたい場合はこの仕様で実装してください。
Itemに配列以外のものを入れる
Itemに配列を入れるのをやめて別の手段を用いる方法もあります。
といいつつ真っ先に思いつくCollectionは元から要素の書き換えができないため、
それ以外の以下のようなパターンが考えられます。
- Dictionaryを出力する列数分作る
- Itemにクラスを入れる
- ItemにもDictionaryを入れる
◇ Dictionaryを列数分作成するパターン

◇ Itemに自作クラスを格納するパターン

◇ ItemにさらにDictionaryを格納するパターン

◇ Itemに配列(Array)を格納するパターン

今回の配列を入れるパターンと合わせて合計4つのやり方がありますが、
どれが優れているという訳ではなくそれぞれメリットデメリットがあります。
これらのサンプルコードを以下の記事で紹介していますので、
画像を見て、設計が分かりやすそうなコードをまずは採用してみてください。