2012-06-20 109 views
2

我有一個項目在過去的幾年中已經發生了一些變化和修改,並且從一個代碼模塊到另一個代碼模塊非常不規範。在某些情況下,我使用了Scripting.Dictionary對象,而在其他情況下,我有一個Collection對象。對於其中的每一個,有時會按計數進行迭代(即For i = 1 to Obj.Count),有時則會由For...Each進行迭代。通過Scripting.Dictionary/Collection對象迭代

我想盡可能多地應用相同的邏輯以使未來的更改有希望更加無縫,但我不確定哪種方法最好。 (我相信一些特定的情況下做了一個或另一種方法,但我也非常確定一些代碼可以使用任何可用的方法。)

我試着創建一個測試子,以幫助我確定哪個這些方法的效果最好,但結果有些不一致。總的來說,看起來循環遍歷每個ItemDictionary更快,但在某些情況下,我的測試顯示通過每個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

回答

2

除非你知道一個事實一個給定的語句或程序的執行時間是問題,你不應該浪費你的時間在優化。首先設計和調試,然後如果你認爲事情太慢(它們可能不會),配置文件,然後才進行優化(執行時間通常會浪費在與你想象的完全不同的地方)。

For Each構造簡潔而整齊。不使用它的唯一原因是如果您要刪除正在循環播放的集合中的項目。那麼你有可能跳過某些項目。如果您計劃刪除項目,請向後循環索引。

+0

據我所知,速度並不是問題,而且所有事情都按預期工作。我對改變事物的唯一興趣是使所有模塊儘可能的相似和一致。我認爲,雖然我在這裏,但我不妨尋找可以做到的最快捷的選擇。 – Gaffi

+0

一點;你的'「Coll1 for x to y:」'使用'Coll1(CStr(j))'這是一個*鍵*查找,而不是索引查找,因爲我認爲你假設;如果你重構那段代碼(並從索引'1'開始),你會得到一個非常不同的(可怕的)(可怕的) )結果(其鏈接列表,獲取第n個項目是沿着鏈條跳轉) - 您是專注於基於索引的查找還是關聯的鍵? –

+0

@AlexK。這個答案取決於它被使用的時間(它可以在這個特定的項目中),但我認爲在大多數情況下沒有使用密鑰。很多時候,因爲'集合'允許在添加時有空的參數,所以後面的代碼甚至不知道要查找什麼鍵(另一點我會盡可能標準化)。 – Gaffi