「あぁ、もう!『支店ごと』の『商品カテゴリごと』の売上を集計するのに、コードがスパゲッティ状態だよ……」
実務の現場では、このようなデータ集計に関する悩みが頻繁に聞かれます。
複数の条件が重なるデータ集計をしようとすると、If文が何重にも重なったり、2次元配列のインデックスの管理で混乱したりしがちになりますよね。
実は私もかつて、同じような課題に直面したことがあります。 複雑な集計を2次元配列で処理しようとして、参照エラーを連発したり…。当時の自分にぜひ伝えたかった解決策が、今回ご紹介するテクニックになります。
それが、Dictionaryの中にさらにDictionaryを格納する「入れ子構造(ネスト)」という手法になります。
これを使えば、人間が頭で考えるのと同じ感覚でデータを整理でき、処理速度も爆速になります。
ただでさえ処理速度の早いDictionaryがさらに速くなりますまさに、業務効率化の強力な味方になります。
1. Dictionaryの「入れ子構造」とは?
「Dictionary(連想配列)」は、よく「名前のついた引き出し」に例えられます。
通常は「商品名(キー)」を入れると「価格(値)」が返ってきます。
この仕組みを一歩進めて、「大きな引き出しの中に、さらに小さな引き出しを入れる」のが入れ子構造です。
- 1階層目(親Dictionary):支店名(東京、大阪、名古屋など)
- 2階層目(子Dictionary):カテゴリ(PC、事務用品、家具など)
これで「東京支店の、PCの売上額はいくらか?」という探し方ができるようになります。
2. なぜ2次元配列ではなくDictionaryの入れ子なのか?
2次元配列の場合、データを「3行目の2列目」のように行と列の「インデックス番号」で指定する必要があります
しかし、元データの行や列が追加されたり順番が変更されたりすると、番号がズレてしまい、予期せぬエラーや計算ミスの原因になります。
これに対してDictionaryは、固有の「名前(キー)」で直接データを指定します。
「東京支店の中のPC」と具体的な名前で直接アクセスできるため、データの並び順を気にする必要がありません。
これが、実務の現場でミスを劇的に減らす最大のメリットになります。
3. 【コピペOK】実務で使える実装サンプルコード
紹介するコードは、順序の異なる売上リストから「支店名」と「商品名」の2つの条件に一致する合計金額を効率的に集計するサンプルになります。
Sub NestedDictionarySample()
' Dictionaryを使うための準備
Dim mainDict As Object
Set mainDict = CreateObject("Scripting.Dictionary")
Dim subDict As Object
Dim branchName As String
Dim productName As String
Dim salesAmount As Long
Dim i As Long
' サンプルデータ(2行目から11行目までデータがあると仮定)
' A列:支店名、B列:商品名、C列:売上金額
For i = 2 To 11
branchName = Cells(i, 1).Value
productName = Cells(i, 2).Value
salesAmount = Cells(i, 3).Value
' --- ここからが「入れ子」の核心部 ---
' 1. 対象の支店キーが存在しない場合、新しい子Dictionaryを生成
If Not mainDict.Exists(branchName) Then
Set subDict = CreateObject("Scripting.Dictionary")
mainDict.Add branchName, subDict
End If
' 2. 親Dictionaryから対象支店の子Dictionaryをオブジェクトとして取得
Set subDict = mainDict(branchName)
' 3. 子Dictionary内の該当商品に対して金額を加算(未存在の場合は自動追加) ' (商品がなければ自動で追加、あれば加算)
subDict(productName) = subDict(productName) + salesAmount
Next i
' --- 結果の取り出し方 ---
' 「東京支店」の「ノートPC」の合計を表示
If mainDict.Exists("東京支店") Then
MsgBox "東京支店のノートPC売上合計は: " & mainDict("東京支店")("ノートPC") & "円です"
End If
End Sub
4. スムーズに理解するためのポイント
この入れ子構造を学ぶ上で、多くの方が戸惑いやすいのが、最後の結果表示(MsgBox)に登場したmainDict(“東京支店”)(“ノートPC”)という記述、つまり概念的な表現で言うところのmainDict(branchName)(productName)というカッコが連続する独特の構文だと思います。
今回のサンプルコードの集計部分では、読みやすさとエラー回避のために一度subDictという変数に切り分けて処理していますが、本質はこの「カッコを2つ繋げる形」にあります。
' 変数subDictを使わずに、1行で直接加算する記述例
mainDict(branchName)(productName) = mainDict(branchName)(productName) + salesAmount
通常のVBAコードではあまり見かけない記述ですよね。でも、仕組みはシンプル。
mainDict(branchName)という記述自体が、内部に格納されている「子Dictionary」のオブジェクトそのものを指しています。
そのため、後ろに続けてもう一つのカッコ(キー)を付与することで、子Dictionaryの内部にある特定の値へダイレクトにアクセスできます。
実務では、コードの読みやすさやエラー回避(引き出しがまだ作られていない際のエラー)のために、一度変数に切り分ける手法が安全ですが、構造としては「カッコを2つ繋げて深い階層へアクセスできる」という点を押さえておくと、入れ子構造への理解がグッと深まります!
5. まとめ
Dictionaryの入れ子構造をマスターすることで、VBAを活用したデータ処理の幅は一気に広がります。
- 「番号」ではなく「名前」で管理できるからミスが激減。
- If文だらけの迷路から脱出できる。
- 数万件のデータも数秒で集計完了。
まずは、実務でよくある「部署ごと」や「担当者ごと」の身近なクロス集計から試してみてはいかがでしょうか。
一度この便利さを知ってしまうと、もうただの2次元配列には戻れなくなるはずです!
VBAを独学で学び、業務自動化に5年以上携わってきた私が、「本当に実務で役立った!」と感じた2冊を紹介します。 もう本選びで失敗したくない方は、よければ参考にしてみてください。

コメント