和風スパゲティのレシピ

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

Dictionary内の配列は要素の書き換えが出来ない

知らずに落ちると抜け出せなくなる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

このコードは、

  1. Itemプロパティにより複製された配列の第1要素に5を代入
  2. この配列はどこにも保存されないためその場で破棄

という手順で処理されるコードになってしまっています。


特に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を列数分作成するパターン
Dictionaryを列数分作成するパターン

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

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

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

今回の配列を入れるパターンと合わせて合計4つのやり方がありますが、
どれが優れているという訳ではなくそれぞれメリットデメリットがあります。


これらのサンプルコードを以下の記事で紹介していますので、
画像を見て、設計が分かりやすそうなコードをまずは採用してみてください。