' This code is for early binding; set reference to Microsoft Scripting Runtime library
Option Explicit
Private Sub CompareObjects()
' This sub actually runs the tests
Dim coll As Collection
Dim dic As Scripting.Dictionary
Dim Counter As Long
Dim RowCounter As Long
Dim ColCounter As Long
Dim StartCollection As Date
Dim EndCollection As Date
Dim StartDicAdd As Date
Dim EndDicAdd As Date
Dim StartDicItem As Date
Dim EndDicItem As Date
Dim StartDicExists As Date
Dim EndDicExists As Date
Dim arr As Variant
Dim Results() As Long
Dim oRow As ListRow
Const Iterations As Long = 20
Const NumRows As Long = 10000
Const NumCols As Long = 50
With ThisWorkbook.Worksheets("Test Data")
'Remove rows with distinct values written to them
.Range((NumRows + 1) & ":" & .Rows.Count).Delete
StartCollection = Now
' Repeat the test several times to smooth out random fluctuations
For Counter = 1 To Iterations
For ColCounter = 1 To NumCols
' Create Collection
Set coll = New Collection
' Array transfer to speed up process
arr = .Cells(1, ColCounter).Resize(NumRows, 1).Value
' If you attempt to add an item where the key already exists, an error results
On Error Resume Next
For RowCounter = 1 To NumRows
coll.Add arr(RowCounter, 1), CStr(arr(RowCounter, 1))
Next
On Error GoTo 0
' Build an array with the return values and write them to worksheet
ReDim Results(1 To coll.Count, 1 To 1)
For RowCounter = 1 To coll.Count
Results(RowCounter, 1) = coll(RowCounter)
Next
.Cells(NumRows + 2, ColCounter).Resize(UBound(arr, 1), 1).Value = Results
Set coll = Nothing
Next
Next
EndCollection = Now
.Range((NumRows + 1) & ":" & .Rows.Count).Delete
StartDicAdd = Now
For Counter = 1 To Iterations
For ColCounter = 1 To NumCols
' Create Dictionary
Set dic = New Scripting.Dictionary
arr = .Cells(1, ColCounter).Resize(NumRows, 1).Value
' If you attempt to add an item where the key already exists, an error results
On Error Resume Next
For RowCounter = 1 To NumRows
dic.Add arr(RowCounter, 1), arr(RowCounter, 1)
Next
On Error GoTo 0
' Put keys into an array, and write array values to worksheet
arr = dic.Keys
.Cells(NumRows + 2, ColCounter).Resize(dic.Count, 1).Value = Application.Transpose(arr)
Set dic = Nothing
Next
Next
EndDicAdd = Now
.Range((NumRows + 1) & ":" & .Rows.Count).Delete
StartDicItem = Now
For Counter = 1 To Iterations
For ColCounter = 1 To NumCols
Set dic = New Scripting.Dictionary
arr = .Cells(1, ColCounter).Resize(NumRows, 1).Value
' In this approach, we use the Item property's "implicit add" capability. Within
' the loop, the Item property either reassigns the item to the key (albeit to same value
' if the key already exists, or creates a new key/item pair if not
For RowCounter = 1 To NumRows
dic.Item(arr(RowCounter, 1)) = arr(RowCounter, 1)
Next
arr = dic.Keys
.Cells(NumRows + 2, ColCounter).Resize(dic.Count, 1).Value = Application.Transpose(arr)
Set dic = Nothing
Next
Next
EndDicItem = Now
.Range((NumRows + 1) & ":" & .Rows.Count).Delete
StartDicExists = Now
For Counter = 1 To Iterations
For ColCounter = 1 To NumCols
Set dic = New Scripting.Dictionary
arr = .Cells(1, ColCounter).Resize(NumRows, 1).Value
' In this approach, we test for existence first; if the key does not exist, we add the item
For RowCounter = 1 To NumRows
If Not dic.Exists(arr(RowCounter, 1)) Then
dic.Add arr(RowCounter, 1), arr(RowCounter, 1)
End If
Next
arr = dic.Keys
.Cells(NumRows + 2, ColCounter).Resize(dic.Count, 1).Value = Application.Transpose(arr)
Set dic = Nothing
Next
Next
EndDicExists = Now
End With
' For each of the four approaches, write a record to the Results worksheet
With ThisWorkbook.Worksheets("Results")
Set oRow = .ListObjects("Stats").ListRows.Add(AlwaysInsert:=True)
oRow.Range(1, 1) = StartCollection
oRow.Range(1, 2) = "Collection"
oRow.Range(1, 3) = EndCollection - StartCollection
Set oRow = .ListObjects("Stats").ListRows.Add(AlwaysInsert:=True)
oRow.Range(1, 1) = StartCollection
oRow.Range(1, 2) = "Dictionary Add"
oRow.Range(1, 3) = EndDicAdd - StartDicAdd
Set oRow = .ListObjects("Stats").ListRows.Add(AlwaysInsert:=True)
oRow.Range(1, 1) = StartCollection
oRow.Range(1, 2) = "Dictionary Item"
oRow.Range(1, 3) = EndDicItem - StartDicItem
Set oRow = .ListObjects("Stats").ListRows.Add(AlwaysInsert:=True)
oRow.Range(1, 1) = StartCollection
oRow.Range(1, 2) = "Dictionary Exists"
oRow.Range(1, 3) = EndDicExists - StartDicExists
End With
End Sub
Sub CompareObjectsMulti()
' Use this to run the test multiple times
Dim Iterations As Long
Dim Counter As Long
On Error GoTo ErrHandler
Iterations = InputBox("How many trials do you want (each can take 2-4 minutes)", "Compare", 10)
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
For Counter = 1 To Iterations
CompareObjects
Next
ErrHandler:
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
End With
MsgBox "Done"
End Sub
Sub CompareObjectsSingle()
' Use this to run the test one time
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
CompareObjects
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
End With
MsgBox "Done"
End Sub