DictionaryとCollectionの違い(特にAddメソッドと引数Key)についてわかります。
DictionaryとCollectionのメリットデメリットを分析し、どちらを使うべきかがわかります。
-
Dictionaryオブジェクト
引数はKey,Itemの順番
Key,Itemどちらも必須
Keyには何でも代入できる(オブジェクトも!!) -
Collectionオブジェクト
引数はItem,Keyの順番
Keyは省略可
Keyには数値、日付は代入できない。文字列はOK!! -
速度はKeyに代入しなければCollectionオブジェクトの方が速い
ただし、そこまで気にしなくてもいい。どっちも速い! -
どちらを使用するべきか
リスト作成であればDictionaryオブジェクトが無難。重複ありであればどちらでもいい。
Keyを使った連想配列を使用する場合はDiciotnaryの方が便利。
Keyを使うかどうかが判断基準となる
こんにちは、hokkyokunです。
みなさんはDictionaryオブジェクトとCollectionオブジェクトどっち使ってますか?
似たようなオブジェクトですが、
実務的には大きく違う点があります。
整理していきましょう。
CollectionとDictionaryのAddメソッド(追加方法)は違う
構文を整理しましょう。
Collectionオブジェクト
Collectionオブジェクト.Add( Item , [Key] , [Before] , [After])
Dictionaryオブジェクト
Dictionaryオブジェクト.Add(Key , Item)
違いをまとめてみました。
ここが一番大事なところです
Collectionオブジェクトは引数Keyの取扱に注意
Keyに数値を入れるとエラー
Collectionオブジェクトの引数Keyに数値を入力するとエラーが生じます。
実験してみましょう
下記のような表を作ります。
番号(数値)をKeyに、果物(文字列)をItemに入れてみます。
Sub CollectionのKeyに数値を代入()
Dim Rng As Range 'Collectionに取り込む変数
Dim r As Range 'For eachで使う変数
Dim Coll As New Collection 'Collectionのインスタンス
'Collectionに取り込む範囲をセット
Set Rng = ActiveSheet.Range("A2:A5")
'Itemに文字列(果物)、Keyに数値(番号)を入れてみる
For Each r In Rng
Coll.Add Item:=r.Offset(, 1).Value, Key:=r.Value
Next
End Sub
エラーが発生しました。
Keyに文字列ならエラーでない
上記と逆に
果物(文字列)をKeyに、番号(数値)をItemに代入してみます。
Sub CollectionのKeyに文字列を代入()
Dim Rng As Range 'Collectionに取り込む変数
Dim r As Range 'For eachで使う変数
Dim Coll As New Collection 'Collectionのインスタンス
Dim myKey As String 'Collectionに取り込むKey
Dim msg As String 'メッセージボックス用変数
'Collectionに取り込む範囲をセット
Set Rng = ActiveSheet.Range("A2:A5")
'Itemに数値(番号)、Keyに文字列(果物)を入れてみる
For Each r In Rng
myKey = r.Offset(, 1).Value
Coll.Add Item:=r.Value, Key:=myKey
'取り込むKeyとItemをメッセージボックス用の変数に代入
msg = msg & vbCrLf & "Key:Item=" & myKey & ":" & Coll(myKey)
Next
MsgBox msg
End Sub
うまく処理できました
CollectionオブジェクトはItemを取り出すためのツール
Collectionオブジェクトに数値を入れることは出来ませんでした。
Keyは省略するとインデックス番号を1から入れていくことになるので、
勝手に数値を入れることが出来ない仕様になっているんだと思います。
また、CollectionオブジェクトからKeyを取り出すメソッドはありませんでした。
CollectionオブジェクトはKeyを取り出してどうこうすることを想定しておらず、
あくまでItemを取り出すためのツールのようです。
Dictionaryは何でもOK
Dictionaryは自由度高しです。
Keyに何を入れてもいいし、Keyを取り出すことも可能です。
上記の例で処理して見ましょう。
Sub DictionaryのKeyに数値を代入()
Dim Rng As Range 'Dictionaryに取り込む範囲の変数
Dim r As Range 'For eachで使う変数
Dim Dic As New dictionary 'Dictionaryのインスタンス
Dim msg As String 'メッセージボックス用変数
Dim i As Long
'Dictionaryに取り込む範囲をセット
Set Rng = ActiveSheet.Range("A2:A5")
'Keyに数値(番号)、Itemに文字列(果物)を入れてみる
For Each r In Rng
Dic.Add Key:=r.Value, Item:=r.Offset(, 1).Value
msg = msg & vbCrLf & "Key:Item=" & Dic.Keys(i) & ":" & Dic.Item(Dic.Keys(i))
i = i + 1
Next
MsgBox msg
End Sub
Keyに数値を入れてみましたが、大丈夫でした。
速度はどっちが速い?
速度を測定してみました。
条件としては
1000行分の文字列(リンゴ1~リンゴ1000)を
- CollectionはItemに取り込み
- DictionaryはKeyとItemに取り込み
これを500回繰り返したときにかかった時間を計測しました。
Collectionの速度
Sub 速度測定Collection()
Dim Rng As Range '取り込む範囲の変数
Dim r As Range 'For each用の変数
Dim Coll As Collection 'Collectionのインスタンス
Dim startTime As Date '開始時間の変数
Dim endTime As Date '終了時間の変数
Dim myTime As Date '終了時間-開始時間
Dim i As Long '繰り返し用の変数
'開始
startTime = Time
'取り込む範囲
Set Rng = ActiveSheet.Range("A2:A1001")
'Itemに1000行取り込み×500回
For i = 1 To 5000
Set Coll = New Collection
For Each r In Rng
Coll.Add r.Value
Next
Next i
'終了
endTime = Time
'かかった時間
myTime = Format(endTime - startTime, "hh:nn:ss")
MsgBox myTime
End Sub
Collectionは15秒でした。
Dictionaryの速度
Sub 速度測定Dictionary()
Dim Rng As Range '取り込む範囲の変数
Dim r As Range 'For each用の変数
Dim Dic As dictionary 'Dictionaryのインスタンス
Dim startTime As Date '開始時間の変数
Dim endTime As Date '終了時間の変数
Dim myTime As Date '終了時間-開始時間
Dim i As Long '繰り返し用の変数
'開始
startTime = Time
'取り込む範囲
Set Rng = ActiveSheet.Range("A2:A1001")
'KeyとItemに1000行取り込み×500回
For i = 1 To 5000
Set Dic = New dictionary
For Each r In Rng
Dic.Add r.Value, r.Value
Next
Next i
'終了
endTime = Time
'かかった時間
myTime = Format(endTime - startTime, "hh:nn:ss")
MsgBox myTime
End Sub
Dictionaryは31秒でした。
DictionaryよりCollectionのほうが速い?
CollectionはDictionaryの半分程度の時間で処理できました。
Collectionの方が速いということでしょうか?
厳密に言うと違います。
CollectionはItemにしか取り込み作業をしていないのに対し、DictionaryはKeyとItem両方に取り込んでいます。
これが原因でCollectionは早く処理が終わっていると思われます。
この証拠に、ColletionでKeyにも取り込みをやってみましたが、
時間は49秒でした(Dictionaryよりも遅いという結果です)。
じゃあ、Dictionaryのほうが速いのかというと
これも違うと思います(どっちやねん)。
keyを使わないでItemにしか取り込み作業をしないということも想定されます。
例えば、重複ありのリスト作成なんかはkeyは使わなくても処理できます。
いいたいことは
目的次第でどちらが適切か変わるということです。
ただし、どちらも超高速ですので、あまりこの処理で待つということはないかもしれません。
Collectionオブジェクトは要素の順番を変えられる
上記の通り、CollectionオブジェクトにはAddメソッドに引数が多く用意されています。
BeforeとAfterですね。
これらをうまく使うことでAddした順番にかかわらず、要素の順番をある程度編集することができます。
方法は引数BeforeもしくはAfterに何番目の前、もしくは後ろに入れるか指定してあげます。
具体的にみてみましょう。
リンゴ、バナナという文字列をItemに取り込んでみます。
当然1番目にリンゴ、2番目にバナナが入ります。
最後にキウイを取り込む際、一番目の要素にしたいとします。
Collectionオブジェクト.Add Item:=”キウイ”,Before:=1
として指定してあげます。
Sub 順番()
Dim Coll As New Collection
Coll.Add Item:="リンゴ"
Coll.Add Item:="バナナ"
Coll.Add Item:="キウイ", Before:=1
End Sub
このように1番目にリンゴ、2番目にバナナが入ります。
1番目にキウイ、2番目にリンゴ、3番目にバナナという感じで
順番を編集できました。
DictionaryとCollectionのメリットデメリット
メリットデメリットをまとめてみました。
お勧めの使い方
考えるポイントはKeyを使う必要があるかどうか
だと思います。
- 使う→Dictionary
- 使わない→Collection
という感じです。
リスト作成はDictionaryが無難(重複ありならCollectionでも大丈夫)
リスト作成に関して言えばDicitonaryが無難です。
というか、これ一択でいった方がいいです。
Collectionでは
Keyには文字列しか入らないので、
数値や日付の重複なしリストは作れません。
重複ありのリストであればCollectionでも使えますし、
Dictionaryより早く処理できると思われます。
ただ、使い分けるメリットはさほどないので、
Dictionaryを使ってリスト作った方が何かと都合がよいと思います。
Key、Itemの関係で連想配列を使うならDictionaryオブジェクト
CollectionオブジェクトはどうしてもKeyの扱いが限定的なので、
やりたいことが出来ない可能性があります。
また、速度も決して速くはないので、Dictionaryオブジェクトを使うほうがいいかもしれません。
ただ、エクセルのようなスプレッドシートがすでに連想配列のようになっているので、
例えばA列の値を検索して、その右(B列)の値を取り出すということをやれば無理して連想配列を使う必要もなくなります。
速度やコード量の問題もあるので、覚えなくていいわけではないですが、
優先して学習することではないとは思います。
Collectionは要素の編集ができることが役に立つ?
かなりニッチな需要ですが、
後からAddで追加した要素を先頭に持ってきたいとか、
そういう処理が必要な場合はCollectionを使ってもいいかもしれません。
お勧めはDictionaryを学習しましょう。
知っておくことは大事なのでCollectionを勉強しなくていいわけではないですが、
Dictionaryを先ず学習し、
なれてきたらCollectionを使って
状況により(Keyを使うかどうか、リストは重複ありかなしか)使い分けするとよいと思います。
Dictionaryはお気に入りのオブジェクトですので、使ってみてください。
ではでは