复合的多值搜索比“哑哑循环”更快?

时间:2019-05-24 19:31:00

标签: excel vba

我正在尝试做多列匹配的事情。我什至不知道该怎么称呼,所以我什至不知道如何搜索。 “化合物匹配” ...?

我在工作表(称为“ RPT-保质期”的工作表)中有一堆“候选”数字(每个数字都是25个字符)。在一个不同的工作表(顺便说一句,“ MasterSheet”,它包含数千行或数万行)中,我想确定是否存在以下条件:

是否存在D列等于CANDIDATE_NUMBER且F列=“香蕉”或“橙色”的行? (答案可以是MasterSheet中的行值)

(注意:F列中将包含“香蕉”或“橙色”以外的值,我必须忽略它们。)

现在,我以非常愚蠢的方式做到这一点:

' Now loop through each of the candidates and hunt for TRANSACTION TYPES that match the ScanID,
' and are either SCHEDULED or DEPLOYED. These are items that ARE NOT STALE. Repair their flags.
  Dim LastRowOfCandidates As Long
  Dim ShelfAgeCounter As Long
  Dim MastersheetTransactionRowIndex As Long
  Dim CandidateScanID As Long
  Dim ItemResolved As Boolean
  LastRowOfCandidates = Worksheets("RPT - Shelf Age").Cells(Rows.Count, 1).End(xlUp).Row
   MsgBox ("There are " & LastRowOfCandidates & " rows of complete data in this report." & vbCrLf)
  For ShelfAgeCounter = 3 To LastRowOfCandidates ' cycle through each candidate
    ItemResolved = False
    TargetRow = 2
    MastersheetTransactionRowIndex = Worksheets("RPT - Shelf Age").Cells(ShelfAgeCounter, 1) ' this is the row in which the candidate appears on the MasterSheet
    CandidateScanID = MastersheetTransactionRowIndex = Worksheets("RPT - Shelf Age").Cells(ShelfAgeCounter, 4) ' the ScanID to hunt for
     'Search the MasterSheet for any occurrence of CandidateScanID where the action is SCHEDULE or DEPLOYED
      Do Until Worksheets("MasterSheet").Cells(TargetRow, 1) = "" Or ItemResolved = True
        If Worksheets("MasterSheet").Cells(TargetRow, 4) = CandidateScanID And Worksheets("MasterSheet").Cells(TargetRow, 6) = "Scheduled for Delivery" Then
          'Worksheets("MasterSheet").Cells(MastersheetTransactionRowIndex, 37) = ""
          ItemResolved = True
        End If
        If Worksheets("MasterSheet").Cells(TargetRow, 4) = CandidateScanID And Worksheets("MasterSheet").Cells(TargetRow, 6) = "Equipment Deployed" Then
          Worksheets("MasterSheet").Cells(MastersheetTransactionRowIndex, 37) = ""
          ItemResolved = True
        End If
        TargetRow = TargetRow + 1
      Loop ' finished looking for a match on MasterSheet
  Next

现在,这可行,但是ho,这需要很长时间。

考虑到这是Excel,它可能有非常快的方法来查找其自己的表中的数据,有没有一种方法不需要要求最长搜索时间=候选数* MasterSheet行数

谢谢你!

-=-=-=-=-=-=-

附录:

这是整个子项,包括尝试使用AUTOFILTER:

Private Sub Worksheet_Activate()
  Worksheets("RPT - Shelf Age").Rows("3:5000").EntireRow.Delete ' I REALLY hope there aren't more than 5000 stale items!
  Worksheets("RPT - Shelf Age").Range("A3").Activate
  Dim CurrentReportRow As Long
  Dim TargetRow As Long
  CurrentReportRow = 3
  TargetRow = 2
  ' Pull in all the CANDIDATE items from the Master Sheet that have perhaps not yet been reconciled
  ' This is not a full data set because I only need a few values to scrub through Candidates.
    Do Until Worksheets("MasterSheet").Cells(TargetRow, 1) = ""
      If Worksheets("MasterSheet").Cells(TargetRow, 37) = 1 Then
        Worksheets("RPT - Shelf Age").Cells(CurrentReportRow, 1) = TargetRow
        Worksheets("RPT - Shelf Age").Cells(CurrentReportRow, 2) = Left(Worksheets("MasterSheet").Cells(TargetRow, 4), 10)
        Worksheets("RPT - Shelf Age").Cells(CurrentReportRow, 3) = Mid(Worksheets("MasterSheet").Cells(TargetRow, 4), 12, 11)
        Worksheets("RPT - Shelf Age").Cells(CurrentReportRow, 4) = Worksheets("MasterSheet").Cells(TargetRow, 4)
        CurrentReportRow = CurrentReportRow + 1
      End If
      TargetRow = TargetRow + 1
    Loop

MsgBox ("Hold up there a sec, hoss!") ' I include this test stop to let me review the table before proceeding.

    Dim wb As Workbook
    Dim wsMaster As Worksheet
    Dim wsRPT As Worksheet
    Dim rFound As Range
    Dim aCandidateIDs As Variant
    Dim vID As Variant
    Set wb = ActiveWorkbook
    Set wsMaster = wb.Worksheets("MasterSheet")
    Set wsRPT = wb.Worksheets("RPT - Shelf Age")
    With wsRPT.Range("D3", wsRPT.Cells(wsRPT.Rows.Count, "D").End(xlUp))
        If .Row < 3 Then Exit Sub   ' No data
        If .Cells.Count = 1 Then
            ReDim aCandidateIDs(1 To 1, 1 To 1)
            aCandidateIDs(1, 1) = .Value
        Else
            aCandidateIDs = .Value
        End If
    End With
    With wsMaster.Range("D1:F" & wsMaster.Cells(wsMaster.Rows.Count, "D").End(xlUp).Row)
        For Each vID In aCandidateIDs
            .AutoFilter 1, vID                                                  'Filter column D for the ID
            .AutoFilter 3, "Scheduled for Delivery", xlOr, "Equipment Deployed" 'Filter column F for the two other strings

             ' Check if there are any results
            On Error Resume Next
            Set rFound = .Offset(1).SpecialCells(xlCellTypeVisible).Cells(1) ' This assumes you only want the first match found.  For all matches, leave off the .Cells(1)
            On Error GoTo 0
            .AutoFilter 'Remove the filter
            If Not rFound Is Nothing Then
                ' Found a match, do something with it here
                ' Because we only returned the first match, no need to iterate over rFound because it will only be 1 cell
                MsgBox "Candidate ID: " & vID & Chr(10) & "Match found on MasterSheet at row: " & rFound.Row
            End If
        Next vID
    End With

    ' Now loop through each of the candidates and hunt for TRANSACTION TYPES that match the ScanID,
    ' and are either SCHEDULED or DEPLOYED. These are items that ARE NOT STALE. Repair their flags.
      'Dim LastRowOfCandidates As Long
      'Dim ShelfAgeCounter As Long
      'Dim MastersheetTransactionRowIndex As Long
      'Dim CandidateScanID As Long
      'Dim ItemResolved As Boolean
      'LastRowOfCandidates = Worksheets("RPT - Shelf Age").Cells(Rows.Count, 1).End(xlUp).Row
      ' MsgBox ("There are " & LastRowOfCandidates & " rows of complete data in this report." & vbCrLf)
      'For ShelfAgeCounter = 3 To LastRowOfCandidates ' cycle through each candidate
        'ItemResolved = False
        'TargetRow = 2
        'MastersheetTransactionRowIndex = Worksheets("RPT - Shelf Age").Cells(ShelfAgeCounter, 1) ' this is the row in which the candidate appears on the MasterSheet
        'CandidateScanID = MastersheetTransactionRowIndex = Worksheets("RPT - Shelf Age").Cells(ShelfAgeCounter, 4) ' the ScanID to hunt for
        ' Search the MasterSheet for any occurrence of CandidateScanID where the action is SCHEDULE or DEPLOYED
          'Do Until Worksheets("MasterSheet").Cells(TargetRow, 1) = "" Or ItemResolved = True
            'If Worksheets("MasterSheet").Cells(TargetRow, 4) = CandidateScanID And Worksheets("MasterSheet").Cells(TargetRow, 6) = "Scheduled for Delivery" Then
              'Worksheets("MasterSheet").Cells(MastersheetTransactionRowIndex, 37) = ""
              'ItemResolved = True
            'End If
            'If Worksheets("MasterSheet").Cells(TargetRow, 4) = CandidateScanID And Worksheets("MasterSheet").Cells(TargetRow, 6) = "Equipment Deployed" Then
              'Worksheets("MasterSheet").Cells(MastersheetTransactionRowIndex, 37) = ""
              'ItemResolved = True
            'End If
            'TargetRow = TargetRow + 1
          'Loop ' finished looking for a match on MasterSheet
      'Next

  ' Empty out this table
    Worksheets("RPT - Shelf Age").Rows("3:5000").EntireRow.Delete ' I REALLY hope there aren't more than 5000 stale items!
    Worksheets("RPT - Shelf Age").Range("A3").Activate
  ' Pull in all the items from the Master Sheet that are still scheduled or deployed.
    CurrentReportRow = 3
    TargetRow = 2
    Worksheets("RPT - Shelf Age").Columns(5).Interior.Color = xlNone
    Do Until Worksheets("MasterSheet").Cells(TargetRow, 1) = ""
      If Worksheets("MasterSheet").Cells(TargetRow, 37) = 1 Then
        Worksheets("RPT - Shelf Age").Cells(CurrentReportRow, 1) = TargetRow ' Transaction ID
        Worksheets("RPT - Shelf Age").Cells(CurrentReportRow, 2) = Left(Worksheets("MasterSheet").Cells(TargetRow, 4), 10) ' REQ
        Worksheets("RPT - Shelf Age").Cells(CurrentReportRow, 3) = Mid(Worksheets("MasterSheet").Cells(TargetRow, 4), 12, 11) ' RITM
        Worksheets("RPT - Shelf Age").Cells(CurrentReportRow, 4) = Worksheets("MasterSheet").Cells(TargetRow, 7) ' Depot timestamp
        Worksheets("RPT - Shelf Age").Cells(CurrentReportRow, 5) = Now - Worksheets("RPT - Shelf Age").Cells(CurrentReportRow, 4) ' Age in days
        If Worksheets("RPT - Shelf Age").Cells(CurrentReportRow, 5) > 3 Then ' if the item is older than 1 day, highlight the cell
          Worksheets("RPT - Shelf Age").Cells(CurrentReportRow, 5).Interior.Color = RGB(255, 0, 0)
        End If
        CurrentReportRow = CurrentReportRow + 1
      End If
      TargetRow = TargetRow + 1
    Loop
    Worksheets("RPT - Shelf Age").Columns(4).NumberFormat = "mmm d, yyyy at h:mm AM/PM"
  ' Sort the table by that age -- oldest presenting first.
    Dim lastrow As Long
    lastrow = Cells(Rows.Count, 1).End(xlUp).Row
    With Workbooks("Equipment_Transactions.xlsm").Sheets("RPT - Shelf Age")
      With .Range("a3").CurrentRegion
        .Sort key1:=.Cells(5), order1:=xlDescending, Header:=xlYes
      End With
    End With
End Sub

编辑(截至2019年5月28日):

是否可以注入一个单元级函数来满足此问题?例如,当我放置在最初的“从仓库中移出”行时,我在AK列中手动添加了“ 1”标志,但也许我可以添加一个单元格级别的命令,该命令的基本内容是“使此单元格自动计算”。如果此工作表上还有其他一行的D列值与此行的D列相同,并且该匹配行的F列具有“预定”或“已部署”,则该值应为空,但否则,该单元格应包含1。“

然后,我可以过滤AK列包含1的所有项目,并且我知道它们已经被对帐了。

2 个答案:

答案 0 :(得分:0)

使用自动过滤器避免循环并找到您的匹配项,如下所示:

<div class="btn-toolbar justify-content-between">
    <form action="{{ route('orders.destroy', ['id' => $order->id]) }}" method="post">
        {{ method_field('UPDATE') }}
        {{ csrf_field() }}
        <div class="btn-group-sm">
            <button type="submit" class="btn btn-success">ok</button>
            <button type="submit" class="btn btn-danger">del</button>
        </div>
    </form>
</div>

答案 1 :(得分:0)

好吧!

首先,感谢所有帮助我探索想法的人。这一切都有帮助。感谢@Chris,他为正确的方向提供了最后的推动。

解决方案结果是:

  1. 将主表的全部内容放入一个巨大的数组中。
  2. 通过阵列完成我所有的模式匹配和搜寻。
  3. 如果数组操作告诉我更改表上的值(每天可能发生5至20次),则对表进行更改。

通过系统的初始时间大约为45秒。通过将所有数据铲入一个数组,然后遍历该数组而不是表,我将其减少了大约五秒钟。我可以进一步削减它,但是说实话,五秒钟循环浏览所有数据可能已经足够了!

赢!