我有一个项目在过去的几年中已经发生了一些变化和修改,并且从一个代码模块到另一个代码模块非常不规范。在某些情况下,我使用了Scripting.Dictionary
对象,而在其他情况下,我有一个Collection
对象。对于其中的每一个,有时会按计数进行迭代(即For i = 1 to Obj.Count
),有时则会由For...Each
进行迭代。通过Scripting.Dictionary/Collection对象迭代
我想尽可能多地应用相同的逻辑以使未来的更改有希望更加无缝,但我不确定哪种方法最好。 (我相信一些特定的情况下做了一个或另一种方法,但我也非常确定一些代码可以使用任何可用的方法。)
我试着创建一个测试子,以帮助我确定哪个这些方法的效果最好,但结果有些不一致。总的来说,看起来循环遍历每个Item
在Dictionary
更快,但在某些情况下,我的测试显示通过每个Item
的循环更快。差异可能取决于系统在任何给定时间发生的一切。
我想知道是否有人有一个明确的答案,哪些方法一直是最快的,假设循环内的所有其他方法都是一样的。或者,有什么方法可以提高我的测试子系统在返回结果时更加一致,以便我可以自己回答这个问题?
测试代码中,我想出了:输出
Option Explicit
Sub Test_Dictionary_Iteration_Speed()
Dim Coll1 As New Collection, Coll2 As New Collection
Dim Dict1 As New Scripting.Dictionary, Dict2 As New Scripting.Dictionary, Dict3 As New Scripting.Dictionary
Dim i As Integer, j As Integer, l As Integer
Dim StartTime As Single, StopTime As Single
Dim v As Variant
Dim Obj As TestObject 'A custom Class that has only one member variable, MainVal, and no functions/subs
For i = 0 To 32766
Set Obj = New TestObject
Obj.MainVal = i
Dict1.Add CStr(i), Obj
Dict2.Add CStr(i), Obj
Dict3.Add CStr(i), Obj
Coll1.Add Obj, CStr(i)
Coll2.Add Obj, CStr(i)
Next i
StartTime = Timer()
For j = 0 To Dict1.Count - 1
l = CInt(Dict1(CStr(j)).MainVal)
Set Obj = Dict1(CStr(l)) 'Do something useful within the loop
Set Obj = Nothing
Dict1.Remove CStr(l)
Next j
StopTime = Timer()
Debug.Print "Dict1 for x to y: " & StopTime - StartTime
StartTime = Timer()
For Each v In Dict2.Items
l = CInt(v.MainVal)
Set Obj = Dict2(CStr(l))
Set Obj = Nothing
Dict2.Remove CStr(l)
Next v
StopTime = Timer()
Debug.Print "Dict2 for each item: " & StopTime - StartTime
StartTime = Timer()
For Each v In Dict3.Keys
l = CInt(Dict3(v).MainVal)
Set Obj = Dict3(CStr(l))
Set Obj = Nothing
Dict3.Remove CStr(l)
Next v
StopTime = Timer()
Debug.Print "Dict3 for each key: " & StopTime - StartTime
'---------- Division between Dictionary and Collection
StartTime = Timer()
For j = 0 To Coll1.Count - 1
l = CInt(Coll1(CStr(j)).MainVal)
Set Obj = Coll1(CStr(l))
Set Obj = Nothing
Coll1.Remove CStr(l)
Next j
StopTime = Timer()
Debug.Print "Coll1 for x to y: " & StopTime - StartTime
StartTime = Timer()
For Each v In Coll2
l = CInt(v.MainVal)
Set Obj = Coll2(CStr(l))
Set Obj = Nothing
Coll2.Remove CStr(l)
Next v
StopTime = Timer()
Debug.Print "Coll2 for each item: " & StopTime - StartTime
Debug.Print vbNewLine & "-----" & vbNewLine
End Sub
真实的例子,显示出 '最佳' 选项并不总是相同的:
Dict1对于x到y:0.2011719
每个项目的Dict2:0.1738281
每个键的Dict3:0.2167969
Coll1 for x to y:0.2050781
Coll2每个项目:0.1386719
Dict1为x至y:0.1875
Dict2每个项目:0.171875
Dict3用于每个键:0.234375
Coll1为x至y:0.2050781
Coll2每个项目:0.1542969
Dict1为x至y:0.25
Dict2每个项目:0.21875
Dict3用于每个键:0.265625
Coll1为x至y:0.234375
Coll2每个项目:0.171875
Dict1 for x to y:0.265625
每个项目的Dict2:0.203125
每个键的Dict3:0。296875
Coll1为x至y:0.234375
Coll2每个项目:0.21875
Dict1为x至y:0.265625
Dict2每个项目:0.1875
Dict3用于每个键:0.234375
Coll1为x至y:0.203125
Coll2每个项目:0.15625
Dict1为x至y:0.28125
Dict2每个项目:0.1875
Dict3用于每个键:0.25
Coll1为x至y:0.234375
Coll2每个项目:0.1875
Dict1为x至y:0.28125
Dict2每个项目:0.21875
Dict3每个键:0.328125
Coll1为X到Y:0.234375
Coll2每个项目:0.234375
据我所知,速度并不是问题,而且所有事情都按预期工作。我对改变事物的唯一兴趣是使所有模块尽可能的相似和一致。我认为,虽然我在这里,但我不妨寻找可以做到的最快捷的选择。 – Gaffi
一点;你的'“Coll1 for x to y:”'使用'Coll1(CStr(j))'这是一个*键*查找,而不是索引查找,因为我认为你假设;如果你重构那段代码(并从索引'1'开始),你会得到一个非常不同的(可怕的)(可怕的) )结果(其链接列表,获取第n个项目是沿着链条跳转) - 您是专注于基于索引的查找还是关联的键? –
@AlexK。这个答案取决于它被使用的时间(它可以在这个特定的项目中),但我认为在大多数情况下没有使用密钥。很多时候,因为'集合'允许在添加时有空的参数,所以后面的代码甚至不知道要查找什么键(另一点我会尽可能标准化)。 – Gaffi