2009-12-07 23 views
6

Wie gut/schnell ist Excel VBA Find vs. binäre Suche? Meine Plattform ist Office 11 | 2003, und ich werde auf drei Datenblättern nach Zeichenfolgen für Spalte A suchen. Gesamtzahl der Zeilen ~ 140.000Excel Find Geschwindigkeit vs VBA binäre Suche?

Wenn es lohnt, welche Bibliothek & Funktionen sollte ich verweisen, um die Sortierung und dann die binäre Suche zu tun? Binäre Suchstrings/Texte haben potentiell Probleme.

... eine Sache muss beachtet werden. Verwenden Sie die binäre Suche Formeln mit sortedtextrequires Vorsicht. Aladin A., Excel MVP

Excel finden:

Worksheets(1).Range("A:A").Find("PN-String-K9", LookIn:=xlValues, LookAt:=xlWhole) 

Antwort

7

viel gegen meine Intuition eine VBA binäre Suche stark ein Excel finden trifft. Zumindest im folgenden Szenario, wo 120.000 6 Zeichenfolgen gleichmäßig auf 3 Arbeitsblätter verteilt sind.

Excel-Suche dauert 1 Minute 58 Sekunden,
VBA binäre Suche dauert 36 Sekunden auf meiner bestimmten Maschine.

Der Vorteil zu wissen, dass der Text in Ordnung ist, überwiegt natürlich den natürlichen Vorteil von Excel. Hinweis Aladin A warnt vor der Sortierreihenfolge.

Option Explicit 

' Call Search to look for a thousand random strings 
' in 3 worksheets of a workbook 

' requires a workbook with 3 sheets and 
' column A populated with values between "00001" to "120000" 
' split evenly 40,000 to a worksheet in ascending order. 
' They must be text, not numbers. 

Private Const NUM_ROWS As Long = 120000 
Private Const SHEET_1 As String = "Sheet1" 
Private Const SHEET_2 As String = "Sheet2" 
Private Const SHEET_3 As String = "Sheet3" 

' This uses VBA Binary Search 
Public Sub Search() 
    Worksheets(SHEET_1).Range("B:B").ClearContents 
    Worksheets(SHEET_2).Range("B:B").ClearContents 
    Worksheets(SHEET_3).Range("B:B").ClearContents 
    DoSearch True  ' change to False to test Excel search 
End Sub 

' Searches for a thousand values using binary or excel search depending on 
' value of bBinarySearch 
Public Sub DoSearch(ByVal bBinarySearch As Boolean) 
    Debug.Print Now 
    Dim ii As Long 

    For ii = 1 To 1000 
     Dim rr As Long 
     rr = Int((NUM_ROWS) * Rnd + 1) 
     If bBinarySearch Then 
      Dim strSheetName As String 
      Dim nRow As Long 
      If BinarySearch(MakeSearchArg(rr), strSheetName, nRow) Then 
       Worksheets(strSheetName).Activate 
       Cells(nRow, 1).Activate 
      End If 
     Else 
      If Not ExcelSearch(SHEET_1, MakeSearchArg(rr)) Then 
       If Not ExcelSearch(SHEET_2, MakeSearchArg(rr)) Then 
        ExcelSearch SHEET_3, MakeSearchArg(rr) 
       End If 
      End If 
     End If 
     ActiveCell.Offset(0, 1).Value = "FOUND" 
    Next 
    Debug.Print Now 

End Sub 

' look for one cell value using Excel Find 
Private Function ExcelSearch(ByVal strWorksheet As String _ 
    , ByVal strSearchArg As String) As Boolean 
    On Error GoTo Err_Exit 
    Worksheets(strWorksheet).Activate 
    Worksheets(strWorksheet).Range("A:A").Find(What:=strSearchArg, LookIn:=xlValues, LookAt:= 
     xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=True 
     , SearchFormat:=False).Activate 
    ExcelSearch = True 
    Exit Function 
Err_Exit: 
    ExcelSearch = False 
End Function 

' Look for value using a vba based binary search 
' returns true if the search argument is found in the workbook 
' strSheetName contains the name of the worksheet on exit and nRow gives the row 
Private Function BinarySearch(ByVal strSearchArg As String _ 
    , ByRef strSheetName As String, ByRef nRow As Long) As Boolean 
    Dim nFirst As Long, nLast As Long 
    nFirst = 1 
    nLast = NUM_ROWS 
    Do While True 
     Dim nMiddle As Long 
     Dim strValue As String 
     If nFirst > nLast Then 
      Exit Do  ' Failed to find search arg 
     End If 
     nMiddle = Round((nLast - nFirst)/2 + nFirst) 
     SheetNameAndRowFromIdx nMiddle, strSheetName, nRow 
     strValue = Worksheets(strSheetName).Cells(nRow, 1) 
     If strSearchArg < strValue Then 
      nLast = nMiddle - 1 
     ElseIf strSearchArg > strValue Then 
      nFirst = nMiddle + 1 
     Else 
      BinarySearch = True 
      Exit Do 
     End If 
    Loop 
End Function 

' convert 1 -> "000001", 120000 -> "120000", etc 
Private Function MakeSearchArg(ByVal nArg As Long) As String 
    MakeSearchArg = Right(CStr(nArg + 1000000), 6) 
End Function 

' converts some number to a worksheet name and a row number 
' This is depenent on the worksheets being named sheet1, sheet2, sheet3 

' and containing an equal number of vlaues in each sheet where 
' the total number of values is NUM_ROWS 
Private Sub SheetNameAndRowFromIdx(ByVal nIdx As Long _ 
    , ByRef strSheetName As String, ByRef nRow As Long) 
    If nIdx <= NUM_ROWS/3 Then 

     strSheetName = SHEET_1 
     nRow = nIdx 
    ElseIf nIdx > (NUM_ROWS/3) * 2 Then 
     strSheetName = SHEET_3 
     nRow = nIdx - (NUM_ROWS/3) * 2 
    Else 
     strSheetName = SHEET_2 
     nRow = nIdx - (NUM_ROWS/3) 
    End If 
End Sub 
+0

Vielen Dank. Bei einem Testfall mit 1000 Beispielen innerhalb von 52000 Möglichkeiten (einzelnes Blatt) habe ich 17 Sekunden für Excel Find vs. 5,5 Sekunden für die binäre Suche bekommen. Das reiben ist die binäre Suche gescheitert 25% der Zeit. Ich denke, das Problem ist, dass die Sortierung von Excel für Strings anders angeordnet ist als die VBA-Vergleiche ">" und "<". – ExcelCyclist

+0

Hat Shell Art von Datensätzen, und die binäre Suche funktioniert super! 2000 zufällige Beispiele, gefunden aus 52000 Zeilen in 36 Sekunden (Excel-Suche) gegenüber 11 Sekunden (binäre Suche). – ExcelCyclist

3

Ich finde die Verwendung des AutoFilters funktioniert viel schneller als die manuelle Suche der Datensätze mit einer beliebigen Methode.

Ich filtere, überprüfe, ob es Ergebnisse gibt, dann gehe weiter. Wenn irgendwelche gefunden werden (durch Überprüfung der Anzahl der Ergebnisse), kann ich den kleinen Teil, der manuell gefiltert wird, durchsuchen oder alle zurückgeben.

Ich benutzte es auf rund 44.000 Datensätze, Suche nach einer Liste von mehr als 100 Teile dagegen.

Binäre Suchen können leicht in Endlosschleifen stecken bleiben, wenn Sie nicht vorsichtig sind.

3

Wenn Sie vlookup mit der sortierten Option verwenden, ist es wahrscheinlich schneller als Ihr vba.