0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[VBA] Dictionaryの使い方。簡単なpivotを作る。

Last updated at Posted at 2021-04-01

この人はVBAがどのくらい出来るのかなって思った時にする質問で
簡単に聞けて、簡単に答えられるのは
「Dictionaryって使ってますか?」ではないでしょうか。
使っているか、使ってないか、なんかよくわからない説明をするか
反応によってその人のレベルがよくわかるようです。

私は「知っているけど使っていない」というなんかよくわからない説明をする派でした。
QiitaでこのDictionaryを使っているサンプルがあって、
私のレベルは「詳しく知らないから使っていない」だったことを知り、Dictionaryについて調べてみましたのでまとめてみます。

簡単にDictionaryについて説明

英語のDictionaryを訳すと「辞書」ですが、他のプログラム言語でいうと、連想配列やHashと呼ばれるものです。辞書は忘れていいと思います。
Hashと同様にkeyとvalueを一つのセットとして、複数セット持つことができます。(VBAではvalueではなくitemと言います。ですが、以下valueで統一します)
keyに重複は許されていません。後述しますが、重複されたデータを格納しようとすると、エラーになるか、valueが上書きされます。
このあたりも他の言語のものと同じだと思います。

使い方

宣言

変数のデータ型をvariantかobjectにする。
CreateObject関数を使う。

  Dim dic As Variant
  Set dic = CreateObject("scripting.dictionary")

配布等を考えるとこのやり方がオススメです。
他の方法は、参照設定をし、dimでnewを使うか、newでインスタンスを作ってください。
私は参照設定方式を使っていませんのでサンプルなしで。

格納

Collectionと違い、keyは数値でも文字列でも大丈夫です。

dic(key) = value
' dic(key)はdic.item(key)の省略版です。

このやり方ならkeyの重複に関しては上書きをしていきます。
上書きが嫌なら dic.exists(key) がkeyの存在有無をbool型で返してくれるので、これを使って格納処理を制御するのがいいと思います。

dic.Add key, value

このやり方だと、すでにkeyが存在する場合エラーが発生します。
基本的に私はaddメソッドを使っていません。
余談ですが、Collectionのaddとはkeyとvalueの並びが逆のようです。

値を呼び出す

dic(key)でvalueを返します。
keyが分かっていて、一つだけならこのやり方ですね。

.keysと.itemsで配列を取得

Dim b As Variant
Dim a As Variant
a = dic.keys
b = dic.items

aにはdicのkeyたちが配列になって入ります。
bにはdicのitemたちが配列になって入ります。

forで回す

VBAではforfor eachがありますが、両方とも使えます。

for next

上記の配列を踏まえてforを使います。

Dim i As Long
Dim a As Variant
a = dic.keys
For i = LBound(a) To UBound(a)
  Debug.Print a(i), dic(a(i))
Next i

私の場合、このやり方をすると頭が混乱してきます。。
aはkeyたちが入っている配列です。
その配列の要素数を使ってforを回します。
iの数値を使ってaのkeyをひとつずつ取り出し、そのkeyを使って元のdicに入っているvalueを参照します。

for each next

VBAの場合、「keyとvalueのセット」を回すことができません。inの後にdic.keysかdic.itemsを指定します。

Dim b As Variant
For Each b In dic.keys
  Debug.Print b, dic(b)
Next b
' bにはkeyが入ります。
' このbを使ってvalueを呼び出すことが可能です。

For Each b In dic.items
  Debug.Print b
Next b
' bにはvalueが入ります。
' この場合はkeyを取り出すことはできません。

下記の例ではin dicになっていますが、dicに.keysが補完されるようです。

Dim b As Variant
For Each b In dic
  Debug.Print b, dic(b)
Next b

注意点

格納されていないkeyを参照すると、
dic(key) = EMPTY
が生成されます。
dic.countで要素数が返ってきますが、上記のEMPTYが入っているものも要素数の中にカウントされることになります。
forで回したりする場合はご注意ください。
For i = 1 To dic.Count
If dic(i) <> 0 Then
'......
End If
Next i
などとすると予期せぬ要素が追加される可能性があります。
Dictionaryにはインデックスという概念はないようです。
keyに連番を振って、それをforで回すという方法ではなく、
for eachでkeyを取得し、keyを使う方法をオススメします。

サンプル(pivot)

サンプルとして簡単なpivotを作ってみます。データの個数を数えるだけのものです。
activesheetのA列にあるデータがそれぞれいくつあるかを数えます。
Dictionaryの使い方は、keyを個々のデータにします。valueはインクリメントしていき、個数を表すようにします。

sample_pivot.bas
Public Sub sample_pivot()
  Dim ws As Worksheet
  Dim y  As Long
  Dim dic, a, k
  Set dic = CreateObject("scripting.dictionary")
  a = ActiveSheet.UsedRange.Value
  For y = LBound(a) To UBound(a)
    k = a(y, 1)
    dic(k) = dic(k) + 1
  Next y
  y = 0
  Set ws = ActiveWorkbook.Worksheets.Add
  For Each k In dic
    y = y + 1
    ws.Cells(y, 1).Value = k
    ws.Cells(y, 2).Value = dic(k)
  Next k
End Sub

出力の前にkeysを取得し、そのkeyを並び替えてから呼び出せばエクセルのpivotのようになります。

おわりに

説明が下手で理解しづらいかもしれませんが、ぜひDictionaryを活用して、ご自身のマクロの中にpivotを組込んでみたりしてください。
間違っているとこや、誤字がありましたらご指摘ください。
Dictionaryのうまい活用方法とかもぜひ教えてください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?