我有一個項目在過去的幾年中已經發生了一些變化和修改,並且從一個代碼模塊到另一個代碼模塊非常不規範。在某些情況下,我使用了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