2016-09-17 51 views
1
查找

我已經被用於查找在Excel工作表中的信息的功能知道: - 鍵可以是一個變量列 - 變量字段可以搜索 表格通常不到一百列,但可以從幾百到幾十萬行進行搜索。在我們最大的文件中,我試圖優化的功能可以使用大約一百萬次。如何使用數組來提高效率,而不是在VBA

閱讀 https://fastexcel.wordpress.com/2011/10/26/match-vs-find-vs-variant-array-vba-performance-shootout/

...並找到我們的函數用於查找(3次)之後,我嘗試使用數組。

這是我寫的

Function getInfo(Key As String, NameField As String, NameKey As String, WksName As String) As Variant 

On Error GoTo Error 

Dim iColumnKEY As Integer 
Dim iColumnFIELD As Integer 
Dim i As Integer 
Dim ListFields, ListKeys As Variant 

ListFields = Worksheets(WksName).Range("A1:ZZ1") 


i = LBound(ListFields, 2) 

'To identify which column contains the Key and which one contains the 
'information we are searching for 
Do While iColumnKEY=0 Or iColumnFIELD=0 
    If i > UBound(ListFields, 2) Then 
     getInfo = "//error\\" 

    ElseIf ListFields(1, i) = NameKey Then 
     iColumnKEY = i 
    ElseIf ListFields(1, i) = NameField Then 
     iColumnFIELD = i 
    End If 
i = i + 1 
Loop 

Dim iROW As Integer 

ListKeys = Worksheets(WksName).Columns(iColumnFIELD) 

i = LBound(ListKeys, 1) 
Do While iROW=0 
    If i > UBound(ListKeys,1) Then 
     getInfo = "//error\\" 

    ElseIf ListKeys(i,1) = Key Then 
     iROW = i 
    End If 
    i = i + 1 
Loop 

getInfo = Worksheets(WksName).Cells(iROW, iColumnFIELD) 

Exit Function 

Error: 
    getInfo = "//error\\" 

End Function 

代碼工作的代碼,但速度很慢。我在做什麼會減慢速度?

它現在不在代碼中,但我確實嘗試了關閉屏幕更新以及自動計算。我沒有看到速度上的差異,這表明我的基本算法是主要問題。

此外,該文章是在2011年。數組仍然比Match/Find快很多?作爲一個方面說明:最終,我會建議讓一個宏在批處理中搜索一系列鍵,而不是爲每個鍵調用該函數。這意味着第一個Do ... While循環對於一個宏只能執行一次,並且只有Do_While for Rows纔會針對每個鍵運行。但是,這在短期內不是一種選擇。

感謝。任何幫助或建議將不勝感激。

回答

0

要了解的部分代碼是最慢的,你可以使用Timer

Dim t as Single 
t = Timer 
' part of the code 
Debug.Print CDbl(Timer - t) ' CDbl to avoid scientific notation 

使用的.Value2代替.Value應該有點幫助:

ListFields = Worksheets(WksName).Range("A1:ZZ1").Value2 

搜索鍵和兩個獨立循環中的字段應該稍微快一點,因爲比較次數會少一些。另外,我不知道這是否是有點慢或更快,但你可以遍歷甚至多維數組:

Dim i As Integer, v ' As Variant 
i = 1 

For Each v in ListFields 
    If v = NameKey Then 
     iColumnKEY = i 
     Exit For 
    End If 
    i = i + 1 
Next 
0

在你的代碼永遠不會使用iColumnKEY

我想這就是你實際上是:

Function getInfo(key As String, NameField As String, NameKey As String, WksName As String) As Variant 

    Dim keyCol As Variant, fieldCol As Variant, keyRow As Variant 
    Dim errMsg As String 

    getInfo = "//error\\" 

    With Worksheets(WksName) 
     With Intersect(.UsedRange, .Columns("A:ZZ")) ' <--| reference a range in passed worksheet cells belonging to columns "A" to "ZZ" from worksheet first used row to last used one and from worksheet first used column to last used one 
      MsgBox .Address 
      fieldCol = Application.Match(NameField, .Rows(1), 0) '<--| look for passed 'NameField' in referenced range 
      If IsError(fieldCol) Then 
       errMsg = " :field column '" & NameField & "' not found" 
      Else 
       keyCol = Application.Match(NameKey, .Rows(1), 0) '<--| look for passed 'NameKey' in referenced range 
       If IsError(keyCol) Then 
        errMsg = " :key column '" & NameKey & "' not found" 
       Else 
        MsgBox .Columns(keyCol).Address 
        keyRow = Application.Match(key, .Columns(keyCol)) '<--| look for passed 'key' in referenced range 'NameKey' column 
        If IsError(keyRow) Then 
         errMsg = " :key '" & key & "' not found in column '" & NameKey & "'" 
        Else 
         getInfo = .Cells(keyRow, fieldCol) '<--| get referenced range "item" 
        End If 
       End If 
      End If 
      If errMsg <> "" Then getInfo = getInfo & errMsg 
     End With 
    End With 
End Function 
+0

謝謝!根據以前的評論,我昨晚做了一些改進。 – Jade

+0

不客氣。您可能想嘗試一下並讓我知道。良好的編碼! – user3598756

+0

@Jade,你通過了嗎? – user3598756