Я последовал совету Тима Уильямса и провел несколько тестов скорости.
Для каждого типа коллекции/массива я сначала добавил 100 000 объектов класса «SpeedTester», который был просто объектом оболочки, содержащим длинную переменную (со свойствами получения/установки). Значением переменной было значение индекса цикла (от 1 до 100 000).
Затем я сделал второй цикл, который включал доступ к каждому объекту в коллекции/массиве и присвоение значения свойства long объекта новой переменной типа long. Я выполнил 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
Методы Collection Indexed и Collection Mapped связаны с хранением объектов в коллекции. Первые были добавлены без ключа, вторые были добавлены с ключом, который представлял собой длинное свойство объекта, преобразованное в строку. Затем доступ к этим объектам осуществлялся в цикле for с использованием индекса от 1 до c.Count.
Следующие два метода были идентичны первым двум в том, как переменные добавлялись в коллекцию. Однако для цикла Get вместо цикла for с индексом я использовал цикл for-each.
Типизированный динамический массив представлял собой пользовательский класс, содержащий массив типа SpeedTester. При каждом добавлении переменной размер массива увеличивался на 1 слот (с помощью ReDim Preserve). Цикл получения был циклом for с индексом от 1 до 100 000, что типично для массива.
Наконец, типизированный статический массив был просто массивом типа SpeedTester, который был инициализирован 100 000 слотов. Очевидно, что это самый быстрый способ. Как ни странно, большая часть прироста скорости была связана с получением, а не с добавлением. Я бы предположил, что добавление будет медленнее для других методов из-за необходимости изменения размера, а получение каждого объекта будет не быстрее, чем динамический массив.
Меня поразила разница между использованием цикла for и цикла for-each для доступа к объектам индексированной коллекции. Я также был удивлен скоростью поиска ключей сопоставленной коллекции - намного, намного быстрее, чем индексация, и сравнима со всеми другими методами, кроме статического массива.
Короче говоря, все они являются жизнеспособными альтернативами для моего проекта (за исключением 1-го и последнего методов, сначала из-за его медлительности, а последний из-за того, что мне нужны массивы с динамически изменяемым размером). Я абсолютно ничего не знаю о том, как на самом деле реализованы коллекции, или о различиях реализации между динамическим и статическим массивом. Любое дальнейшее понимание будет высоко оценено.
РЕДАКТИРОВАТЬ: код самого теста (с использованием динамического массива)
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
person
Swiftslide
schedule
01.09.2012
redim preserve
, если это происходит нечасто и/или вы знаете размер нового массива, и позволит вам продолжать использовать массив (а не коллекцию). - person enderland   schedule 01.09.2012