ぼくLog

子持ち、車持ち、マンション持ちの僕の日常を綴ります。車と、ラクをしたい一心で覚えたエクセルVBAを中心になりそうです。

Collectionは強い味方|エクセルVBA

f:id:yt4u:20160711215232j:plain

Collection は強い味方です

エクセルVBAで、配列はスタメンです、と言っていましたが

yt4u.hatenablog.com

配列の存在価値を脅かす「Collection」というのがいます。



Collection とは

Collection とは何か?

ぼくの理解では、ひとつの箱(オブジェクト)に複数の要素をひとまとめにして扱えるようにしたもの、ということです。

この Collection の概念の中で代表的なものを挙げるとすれば、Worksheetsコレクションではないでしょうか。

つまり、Worksheetsコレクションは、単一のWorksheetオブジェクトの集合体です。


例えばこのコード。

Sub サンプル1()
  Dim lngWS             As Long

  For lngWS = 1 To ThisWorkbook.Worksheets.Count

    MsgBox Worksheets(lngWS).Name

  Next

End Sub

このコードを実行すると、開いているブックに存在するシート名が、順次メッセージボックスで表示されていきます。


Collectionという観点からこのコードを見ると、こういうことになります。

複数のWorksheetオブジェクトを格納したWorksheetsという箱(Worksheetsコレクション)の中から、単一のWorksheetオブジェクトをひとつひとつ取り出す。
そして、取り出したひとつひとつのWorksheetオブジェクトについて、プロパティの取得・設定やメソッドを実行していく。

まさしく、これがCollectionを扱う基本的な動作と言えます。


Collecitonオブジェクトを使ってみる

Worksheetsコレクションは予め用意されたCollectionですが、自分でCollectionを作ることができます。

それがCollectionオブジェクトです。

Sub サンプル2()
  Dim colSample         As Collection
  
  Set colSample = New Collection
  
  With colSample
    .Add Item:="東京都", Key:="a"
    .Add Item:="大阪府", Key:="b"
  End With
  

  MsgBox colSample(1)   '→ダイアログに東京都と表示される

  MsgBox colSample("b") '→ダイアログに大阪府と表示される
  
  
  Set colSample = Nothing
  

End Sub

コレクションを作成した後、Addメソッドを使ってItemを追加します。

このとき、Addした順に自動的にIndexが割り振られ、このIndexを使ってItemを取得できるようになります。

またKeyの設定は任意ですが、設定した場合はKeyを指定してItemを取得できるようになります。

Keyを設定する際は、重複する値を設定することはできません。
一方、Itemは重複して設定することが可能です。


Collectionを配列のように使う

で、このCollectionの特性を活かして、Collectionを一次元配列のように使うことが可能です。


たとえば次のコードを実行してみると、アクティブシートの1列目に1から10000までの数値が表示されるのが確認できると思います。

Sub サンプル3()
  Dim colSample         As Collection
  Const cntX            As Long = 10000
  Dim lngX              As Long

  
  Set colSample = New Collection
  

  For lngX = 1 To cntX
  
    colSample.Add lngX
    
  Next
  
  
  With ActiveSheet
  
    For lngX = 1 To cntX
    
      .Cells(lngX, 1).Value = colSample(lngX)
    
    Next
  
  End With
  
  
  Set colSample = Nothing

End Sub


これって配列っぽいですよね?!

同じことを配列でやってみるとこうなります。

Sub サンプル4()
  Dim lngSample()       As Long
  Const cntX            As Long = 10000
  Dim lngX              As Long
  

  ReDim lngSample(cntX - 1)

  
  For lngX = 1 To cntX
  
    lngSample(lngX - 1) = lngX
  
  Next
  
  
  With ActiveSheet
  
    For lngX = 1 To cntX
    
      .Cells(lngX, 1).Value = lngSample(lngX - 1)
    
    Next
  
  End With
  
End Sub

このサンプルのような簡単なものだとCollectionの使いやすさが伝わらないかな(汗

ぼくが感じるCollectionの使いやすさは、ハコの大きさを考えずにどんどんAddしていけるところですね。

配列の場合、Redim(Preserve)でハコの大きさを先に決めてから値を入れていく必要がありますが、Collectionの場合それが必要なく、単にAddすればいい。

なので、データの大きさがその時々で変わるような場合、Collectionは威力を発揮してくれます。



Collectionの真骨頂はKey

さらにCollectionの威力をに高めてくれるのがKeyの存在です。

最初の、Collectionの説明で触れたように、Keyを指定することで、それと紐づけられたItemを取り出すことができます。

たとえば、太郎が100円、次郎が200円、三郎が300円持ってるとき、太郎と次郎あわせていくらか?というのをCollectionを使って書いてみると

Sub サンプル5()
  Dim colSample         As Collection

  Set colSample = New Collection
  
  colSample.Add 100, "太郎"
  colSample.Add 200, "次郎"
  colSample.Add 300, "三郎"
  
  MsgBox colSample("太郎") + colSample("次郎")
  
  Set colSample = Nothing

End Sub

こんなカンジで表現できますよね。

このようにデータの塊の中からパパッと欲しいものだけを拾ってこれるのはCollectionの強みです。

配列でも同じようなことを再現はできますが、ここまで簡単にはできません。

Collectionの配列的な使い方にKeyが加わることで、威力は絶大になるわけです。


Collectionと配列、どっちが早い?

で、気になるのがCollectionを使った場合の処理時間。

気になりますよね。

Collectionに限らずですけど、オブジェクトって聞くと、なんか処理が遅くなりそうな気がしてしまうのはぼくだけでしょうか?

そこでさっきのサンプルの処理時間を計測してみーたーとーこーろー

回数 Collection 配列
1 0.656秒 0.316秒
2 0.652秒 0.301秒
3 0.699秒 0.313秒
4 0.658秒 0.308秒
5 0.632秒 0.342秒
平均 0.659秒 0.316秒

配列の勝ち!

Collectionは配列の倍の時間が掛かってしまうんですね。

この時間差を大きいと見るか小さいと見るかは、やろうとすることとかデータの大きさによって変わってくると思います。

なので、どっちを使うかに拘りすぎず、その時々で判断していく必要があるってことになってしまうわけですが、ぼくは極力Collectionを使うようにしています。