和風スパゲティのレシピ

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

Dictionaryの要素(Key/Item)をセルに出力する

Dictionaryの要素をシートに出力する方法を解説します。

For Each文で1要素ずつセルへ出力していく方法と、
配列を介して一括でセル範囲に出力する方法の2つがあります。


単純に出力するだけなら後者が簡単で高速ですが、
細かい処理を追加するときは前者の方が扱いやすいです。

状況に応じて使い分けてください。

For Each を用いて全要素をセルに出力する

今回はサンプルとして↓のようなDictionaryをセルに出力します。
Dictionaryのサンプル
これが変数「Dic商品リスト」に格納されていると想定してください。

このDictionary内の要素をFor Each文で取り出すコードがこちらです。

' DictionaryのKeyをセルに出力する
Dim R As Long: R = 2
Dim key商品
For Each key商品 In Dic商品リスト.Keys

    Cells(R, 1) = key商品
    R = R + 1

Next
' DictionaryのItemをセルに出力する
Dim R As Long: R = 2
Dim item個数
For Each item個数 In Dic商品リスト.Items

    Cells(R, 2) = item個数
    R = R + 1

Next

DictionaryはKeys/Itemsメソッドで要素を一次元配列に変換でき、
それをFor Each文で回すことで、1つずつセルに出力していくことができます。


ループに使用する変数は「key」「item」を頭につけておくと、
それがDictionaryの要素であったことがわかって読みやすくなります。

また、これらの変数はStringやLongにしたいところなのですが、
「For Eachで回す変数は何らかのObject型またはVariant型」
という制約がありますので、値をForEachで回す場合はVariantで宣言してください。


上記はKey/Itemを別々に出力していますが、これをセットで出力したい場合は、
Keyでループし、KeyからItemを取得するItemプロパティを使用します。

' DictionaryのKey,Itemを同時にセルに出力する
Dim R As Long: R = 2
Dim key商品
For Each key商品 In Dic商品リスト.Keys
    
    Cells(R, 1) = key商品
    Cells(R, 2) = Dic商品リスト.Item(key商品)
    R = R + 1

Next

こちらもDictioanryの基本コードですのでしっかり覚えておきましょう。


後からコードを追加する際にItem→Keyの取得はできませんので、それを見越して
Itemだけを取得するコードであってもKeyでループしてもいいかもしれません。

' DictionaryのItemをセルに出力する
Dim R As Long: R = 2
Dim key商品
For Each key商品 In Dic商品リスト.Keys
    
    Cells(R, 2) = Dic商品リスト.Item(key商品)
    R = R + 1

Next

お好きな方を採用してください。

 
なお、Dictionaryの省略記法として、

Cells(R, 2) = Dic商品リスト.Item(key商品)
' ↓ Itemは既定のプロパティなので省略可
Cells(R, 2) = Dic商品リスト(key商品)
For Each key商品 In Dic商品リスト.Keys
' ↓ KeysはFor Eachで使うときだけ省略可(非推奨)
For Each key商品 In Dic商品リスト

この2つの省略が可能です。


慣れたら前者はどんどん使っていいと思いますが、
後者はわかりにくいのでやめておきましょう。

詳しく読みたい方はこちらの記事をどうぞ
www.limecode.jp

Keys/Itemsの配列をセル範囲に一括出力する

続いてKeys/Itemsで取得した配列をセル範囲に一括出力するコードがこちらです。

Cells(2, 1).Resize(dic商品リスト.Count).Value _
    = WorksheetFunction.Transpose(dic商品リスト.Keys)

Cells(2, 2).Resize(dic商品リスト.Count).Value _
    = WorksheetFunction.Transpose(dic商品リスト.Items)

 
配列→セル範囲の基本コードである

配列と大きさを合わせたセル範囲.Value = 二次元配列

このコードを利用したコードですね。


まず「二次元配列」ですが、Keys/Itemsは一次元配列を返すメソッドのため、
このままでは縦方向のセル範囲に出力することができません。

といっても縦方向の二次元配列にするのは簡単で、
シート関数のTRANSPOSEを使えば縦方向(n行1列)の二次元配列にしてくれます。


それを「配列と大きさを合わせたセル範囲」に代入すればよいのですが、
こちらも「Resizeプロパティ」を使って簡単に大きさを合わせることができます。

「出力始点セル.Reseze(Dictionaryの要素数)」
と、非常に読みやすいコードになっていますね。


これを「Range(Cells,Cells)方式 + 配列の上限Ubound」でやろうとすると、
凄まじく複雑なコードに仕上がってしまいます。

配列やDictionaryを使うコードを書き始めると同時に、
Resizeプロパティでセル範囲を扱えるようになっておきましょう。


なお、TRANSPOSE関数は要素の上限が65,536という罠があります。

このデータ数では前述のFor Eachでやっても実行時間が膨大になるので、
下記で説明する「一次元配列→二次元配列」の汎用関数で対応してください。

汎用関数として持っておく

Dictionaryを良く扱う方は、今回のコードを汎用関数として持っておきましょう。

' 汎用関数を使用したセル範囲への一括出力
Call Dictionaryの全Keyをセルに出力する(dic商品リスト, Cells(2, 1))
Call Dictionaryの全Itemをセルに出力する(dic商品リスト, Cells(2, 2))
' Dictionary → セル の汎用関数
Sub Dictionaryの全Keyをセルに出力する(出力Dic As Dictionary, 出力始点セル As Range)
    出力始点セル.Resize(出力Dic.Count) = WorksheetFunction.Transpose(出力Dic.Keys)
End Sub
Sub Dictionaryの全Itemをセルに出力する(出力Dic As Dictionary, 出力始点セル As Range)
    出力始点セル.Resize(出力Dic.Count) = WorksheetFunction.Transpose(出力Dic.Items)
End Sub

コードがかなり書きやすく&読みやすくなっているのがわかります。


こういった「簡単だけど書くのが少し手間」なコードは、
関数づくりが簡単な割にメリットが大きいです。

配列・Dictionary周りのコードは汎用関数が便利な場面が多いので、
積極的に自作ライブラリに組み込んでいってください。

汎用関数についてはこちらの記事をどうぞ


また、せっかく汎用関数にするのであれば、
二次元配列→セルの汎用関数を用意し、Dictionaryでもそれを使う方法もあります。

Transposeを使用しない形で書いていますので、
先ほどの上限65,536件問題もこちらの関数であれば発生しません。


コピペでそのまま使えますのでよろしければお持ち帰りいただきつつ、
内容はこちらの記事で解説していますので興味があれば読んでみてください。

' 一次元配列→セルの汎用関数を使用した一括出力
Call 一次元配列をセルに出力する(Cells(2, 1), dic商品リスト.Keys)
Call 一次元配列をセルに出力する(Cells(2, 2), dic商品リスト.Items)
' 一次元配列 → セル
Sub 一次元配列をセルに出力する(出力始点セル As Range, Arr出力配列 As Variant _
    , Optional is縦方向へ出力 As Boolean = True)

    Dim 要素数 As Long: 要素数 = Count配列の要素数(Arr出力配列)
    If is縦方向へ出力 Then
        出力始点セル.Resize(要素数, 1).Value _
            = GetArray一次元配列→n行1列の二次元配列(Arr出力配列)
    Else
        出力始点セル.Resize(1, 要素数).Value = Arr出力配列
    End If
    
End Sub

' 配列要素数の取得
Function Count配列の要素数(Arr, Optional 次元 = 1) As Long
    Count配列の要素数 = UBound(Arr, 次元) - LBound(Arr, 次元) + 1
End Function

' Transpose上限対応用関数
Function GetArray一次元配列→n行1列の二次元配列(Arr As Variant) As Variant
    
    Dim 生成配列()
    ReDim 生成配列(LBound(Arr) To UBound(Arr), 1 To 1)
    
    Dim i As Long
    For i = LBound(Arr) To UBound(Arr)
        生成配列(i, 1) = Arr(i)
    Next
    
    GetArray一次元配列→n行1列の二次元配列 = 生成配列
    
End Function