VBAのDictionaryのItemに動的配列を格納する
C++のmultimapのように、特定のキーに対し、複数のデータをDictionaryに格納できないか?
キー毎にデータ数が異なる場合、最大データ数を求めてから固定長配列を格納するのは無駄だし、
実際にデータがいくつ入っているか先頭から当たっていかないとわからなそう。
それは、やりたくない。
で、動的配列をItemとして格納してみたら、案外あっさりと出来ました。
ワークシートから読み込んだ地名の先頭1文字をキーとして、その地名を配列にしてItemに格納する例です。
Public Sub dicTest()
Dim dicAddress As New Dictionary
Dim sAddress() As String
Dim sKey As String
Dim lItems As Long
Dim sValue As String
Dim lRow As Long
Dim i As Long
lRow = 1
lItems = 0
ReDim sAddress(lItems)
With ThisWorkbook.Worksheets("Sheet1")
sValue = .Cells(lRow, 1).Value
Do Until (Len(sValue) = 0)
sKey = Left$(sValue, 1)
If dicAddress.Exists(sKey) = True Then
'キーありなら、格納されている配列を取得
sAddress = dicAddress.Item(sKey)
lItems = UBound(sAddress) + 1
'配列の要素数をひとつ増やす
ReDim Preserve sAddress(lItems)
Else
'キーなしなら、1個分のデータを格納できるよう、配列を初期化
lItems = 0
ReDim sAddress(lItems)
End If
sAddress(lItems) = sValue
'配列を格納
dicAddress(sKey) = sAddress
lRow = lRow + 1
sValue = .Cells(lRow, 1).Value
'Dictionaryには、コピーされた配列が格納される(ようです)。
'消さなくても試した限りでは問題はなさそうだけど、残して何度も使い回すのは気持ち悪いので消す。
Erase sAddress
Loop
End With
'格納したデータを書き出す
Debug.Print "----- い -----"
For i = 0 To UBound(dicAddress.Item("い"))
Debug.Print dicAddress.Item("い")(i)
Next i
Debug.Print "----- お -----"
For i = 0 To UBound(dicAddress.Item("お"))
Debug.Print dicAddress.Item("お")(i)
Next i
End Sub
テストデータは
---------------------------------
あきる野市
あわら市
あま市
あさぎり町
おいらせ町
いわき市
つくばみらい市
さいたま市
いすみ市
おおい町
いなべ市
いの町
いちき串木野市
---------------------------------
実行結果は、
----- い -----
いわき市
いすみ市
いなべ市
いの町
いちき串木野市
----- お -----
おいらせ町
おおい町
こんな感じ。
ポイントは、
1.キーがあった時の、データ(動的配列)の取り出し方。
2.データを追するのためのReDim PreserveとReDimの使い方。
3.データ読み出し時の指定方法dicAddress.Item("い")(i)
あたりでしょうか。
まあ、ちょっとしたネタなので、「もっといい方法がある」とか突っ込まないで下さい。
こんなのもあります。