私はティム・ウィリアムズのアドバイスに従い、いくつかの速度テストを行いました。
コレクション/配列のタイプごとに、最初にクラス「SpeedTester」の100,000個のオブジェクトを追加しました。これは、長い変数(get / setプロパティを持つ)を保持する単純なシェルオブジェクトでした。変数の値は、ループインデックスの値(1〜100,000)でした。
次に、コレクション/配列内の各オブジェクトにアクセスし、オブジェクトのlongプロパティ値をlong型の新しい変数に割り当てるという2番目のループを実行しました。メソッドごとに3ラウンドを実行し、Andループとgetループの時間を平均しました。
結果は次のとおりです。
Method Avg Add Time Avg Get Time Total Time
Collection Indexed 0.305 25.498 25.803
Collection Mapped 1.021 0.320 1.342
Collection Indexed For Each 0.334 0.033 0.367
Collection Mapped For Each 1.084 0.039 1.123
Dynamic Array Typed 0.303 0.039 0.342
Static Array Typed 0.251 0.016 0.266
CollectionIndexedおよびCollectionMappedのメソッドには、コレクション内のオブジェクトの保持が含まれていました。1つ目はキーなしで追加され、2つ目はオブジェクトのlongプロパティが文字列に変換されたキーで追加されました。次に、これらのオブジェクトは、1からc.Countまでのインデックスを使用してforループでアクセスされました。
次の2つの方法は、変数がコレクションに追加された方法で最初の2つと同じでした。ただし、Getループでは、インデックス付きのforループを使用する代わりに、for-eachループを使用しました。
型指定された動的配列は、SpeedTester型の配列を含むカスタムクラスでした。変数が追加されるたびに、配列のサイズが1スロットずつ拡張されました(ReDim Preserveを使用)。get-loopは、配列で一般的な1〜100,000のインデックスを使用するforループでした。
最後に、型指定された静的配列は、100,000スロットで初期化されたSpeedTester型の配列でした。明らかに、これが最速の方法です。不思議なことに、その速度の向上の多くは、追加ではなく取得にありました。サイズを変更する必要があるため、他のメソッドの追加は遅くなると思いましたが、各オブジェクトの取得は動的配列よりも速くはありません。
インデックス付きコレクションのオブジェクトにアクセスするためにforループとfor-eachループを使用することの違いに驚かされました。また、マップされたコレクションのキールックアップ速度にも驚いていました。インデックス作成よりもはるかに高速で、静的配列を除く他のすべてのメソッドに匹敵します。
要するに、これらはすべて私のプロジェクトの実行可能な代替手段です(最初と最後のメソッドを除いて、最初は速度が遅いため、最後は動的にサイズ変更可能な配列が必要なためです)。コレクションが実際にどのように実装されているか、または動的配列と静的配列の実装の違いについては、まったく何も知りません。さらに洞察をいただければ幸いです。
編集:テスト自体のコード(動的配列を使用)
Public Sub TestSpeed()
Dim ts As Double
ts = Timer()
Dim c As TesterList
Set c = New TesterList
Dim aTester As SpeedTester
Dim i As Long
For i = 1 To 100000
Set aTester = New SpeedTester
aTester.Number = i
Call c.Add(aTester)
Next i
Dim taa As Double
taa = Timer()
For i = c.FirstIndex To c.LastIndex
Set aTester = c.Item(i)
Dim n As Long
n = aTester.Number
Next i
Dim tag As Double
tag = Timer()
MsgBox "Time to add: " & (taa - ts) & vbNewLine & "Time to get: " & (tag - taa)
End Sub
そして、動的配列クラスTesterListの場合:
Private fTesters() As SpeedTester
Public Property Get FirstIndex() As Long
On Error GoTo Leave
FirstIndex = LBound(fTesters)
Leave:
On Error GoTo 0
End Property
Public Property Get LastIndex() As Long
On Error GoTo Leave
LastIndex = UBound(fTesters)
Leave:
On Error GoTo 0
End Property
Public Sub Add(pTester As SpeedTester)
On Error Resume Next
ReDim Preserve fTesters(1 To UBound(fTesters) + 1) As SpeedTester
If Err.Number <> 0 Then
ReDim fTesters(1 To 1) As SpeedTester
End If
Set fTesters(UBound(fTesters)) = pTester
On Error GoTo 0
End Sub
Public Function Item(i As Long) As SpeedTester
On Error GoTo Leave
Set Item = fTesters(i)
Leave:
On Error GoTo 0
End Function
そして最後に、非常に単純なSpeedTesterオブジェクトクラス:
Private fNumber As Long
Public Property Get Number() As Long
Number = fNumber
End Property
Public Property Let Number(pNumber As Long)
fNumber = pNumber
End Property