配列の都度拡張は時間が掛かるのか(実験)

先日から、配列やコレクションの作成に掛かる時間を色々と測定している。
infoment.hatenablog.com
これらを通じて、ふと思いついた。総数が分からないものを配列に格納する際、Redimによる都度拡張は、思ったより時間が掛かっているのではないか。そこで、簡易的な実験を行ってみた。
f:id:Infoment:20181216185306p:plain

総数が分かっている場合

まず測定基準として、こちらを用意した。

Sub test_1()
    Dim i As Long
    Dim seq(1 To 1000000) As Variant
    
    For i = 1 To 1000000
        seq(i) = i
    Next
End Sub

1~100万の要素数を持つ配列を作成。最初から範囲が分かっているので、それに合わせて配列を準備している。商品が100万個あることがわかっているので、最初に箱を100万個準備して箱詰めするイメージ。

測定結果は↓こちら。
f:id:Infoment:20181216185609p:plain

例え要素数が100万でも、実行時間は0.0秒。ほとんど体感できない短時間で、処理が完了する。

配列を都度拡張する場合

次いで、値を一つ入れるたびに、配列を拡張してみた。

Sub test_2()
    Dim i As Long
    Dim seq() As Variant
    ReDim seq(1 To 1)
    
    For i = 1 To 1000000
        seq(i) = i
        ReDim Preserve seq(1 To i + 1)
    Next
    
    ReDim Preserve seq(1 To i - 1)
End Sub

商品が1個出てくるたびに、まず最後の1箱に商品を箱詰めして、次の箱を1個準備する。これを100万回繰り返すイメージ。

測定結果は↓こちら。
f:id:Infoment:20181216190148p:plain

実行時間は25.9秒。250倍以上の時間が掛かっている。100万回の拡張作業が、「塵も積もれば山となる」で効いている。

一旦コレクションに格納する場合

最後に、一旦全てコレクションに格納する方法を試してみた。

Sub test_3()
    Dim i As Long
    Dim col As Collection
    Set col = New Collection
    
    For i = 1 To 1000000
        col.Add i
    Next
    
    Dim seq() As Variant
    ReDim seq(1 To col.Count)
    Dim c As Variant
    
    i = 1
    For Each c In col
        seq(i) = c
        i = i + 1
    Next
End Sub

一旦商品を全て倉庫に入れ、倉庫の中の商品数を数える。そして、その数分だけ箱を準備して箱詰めするイメージ。

測定結果は↓こちら。
f:id:Infoment:20181216190639p:plain

実行時間は0.2秒。実質「2周」しているが、都度拡張より遥かに早い。


100万ものデータを扱うのでなければ、どの方式も差はないかもしれない。だが、どうも処理時間が遅いなと感じたら、敢えてコレクションに格納するという方式を試してみるのもありかもしれない。

参考まで。