空腹おやじのログと備忘録

VBA(主にExcel)でいろいろな実験的な事とか、Linuxのコマンドとか設定とかについて忘れないように、あれこれと・・・

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 PreserveReDimの使い方。
3.データ読み出し時の指定方法dicAddress.Item("い")(i)
あたりでしょうか。

 

まあ、ちょっとしたネタなので、「もっといい方法がある」とか突っ込まないで下さい。

 

こんなのもあります。

z1000s.hatenablog.com