如何使用多维数组搜索多个值?

How can I search for multiple values using multidimensional Array?

此代码现在可以在多个 sheet 中搜索多个值。 我怎样才能修复它以支持同时搜索多个值而不必编写每个值。例如,我想在 A 列中放入我所有的搜索值,然后我单击搜索,它应该同时搜索并给出所有这些值。我应该在代码中更改什么来执行此功能? 请查看代码和图片。

 Dim i, j, k, l, m, n, no_sheets As Variant
 Dim key, cursor, sheetname As Variant
 Dim flag As Variant
 Dim sheet1_count, sheet1_row, row_count As Integer
 Dim Arr() As Variant

     sheet1_count = WorksheetFunction.CountA(ThisWorkbook.Worksheets("sheet1").Range("A:A"))

     no_sheets = 3 ' Number of sheets
     k = 2
     sheet1_row = sheet1_count 'My start in result sheet

     key = ThisWorkbook.Worksheets("sheet1").Range("A" & sheet1_count) ' The value that the user will put in searching sheet in column A

     For i = 2 To no_sheets ' sheet2 then sheet3 then sheet4 then sheet5 ..etc
         flag = False
         sheetname = "Sheet" & i
         row_count = WorksheetFunction.CountA(ThisWorkbook.Worksheets(sheetname).Range("A:A")) ' It's a counter that will contain the range of row A in each sheet
     For j = 1 To row_count 'I'll start from row 1 until the last sheet
         cursor = ThisWorkbook.Worksheets(sheetname).Range("A" & j) 'Searching in column A in each sheet (1st row - last row) and put the value in this variable
             If key = cursor Then ' If the entering value in sheet1 equal the value that we have in current sheet, do the following
             ' Copying the data

             flag = True ' The data found

                  ThisWorkbook.Worksheets("sheet1").Range("A" & sheet1_row) = ThisWorkbook.Worksheets(sheetname).Range("A" & j)
                  ThisWorkbook.Worksheets("sheet1").Range("B" & sheet1_row) = ThisWorkbook.Worksheets(sheetname).Range("B" & j)
                  ThisWorkbook.Worksheets("sheet1").Range("C" & sheet1_row) = ThisWorkbook.Worksheets(sheetname).Range("C" & j)
                  ThisWorkbook.Worksheets("sheet1").Range("D" & sheet1_row) = ThisWorkbook.Worksheets(sheetname).Range("D" & j)
                  ThisWorkbook.Worksheets("sheet1").Range("E" & sheet1_row) = ThisWorkbook.Worksheets(sheetname).Range("E" & j)
                  ThisWorkbook.Worksheets("sheet1").Range("F" & sheet1_row) = ThisWorkbook.Worksheets(sheetname).Range("F" & j)

                 sheet1_row = sheet1_row + 1
                Else

         End If
     Next j 'Go to the next row
Next i 'Go to the next sheet
    MsgBox "finished, Do another search..!"


            If key <> cursor Then
              flag = False  ' If the value not found

                  ThisWorkbook.Worksheets("sheet1").Range("B" & sheet1_row) = "Not found"
                  ThisWorkbook.Worksheets("sheet1").Range("C" & sheet1_row) = "Not found"
                  ThisWorkbook.Worksheets("sheet1").Range("D" & sheet1_row) = "Not found"
                  ThisWorkbook.Worksheets("sheet1").Range("E" & sheet1_row) = "Not found"



            End If



       End Sub

   Sub MatchUnMatch_Click()
Dim i, j, k, l, m, n As Integer
Dim ListA_count, ListB_count, ListC_count, ListD_count, ListE_count As Integer
Dim key, cursor As String
Dim flag As Boolean

ListA_count = WorksheetFunction.CountA(ThisWorkbook.Worksheets("MatchUnmatch").Range("A:A"))
ListB_count = WorksheetFunction.CountA(ThisWorkbook.Worksheets("MatchUnmatch").Range("B:B"))
'ListA_count = ThisWorkbook.Worksheets("MatchUnMatch").Range("A2").End(xlDown).Row
'MsgBox ListA_count & " " & ListB_count
'=======================================================================================================
'
'
' Matching Logic for List 'A' and List 'B'
'
'
'=======================================================================================================
k = 2
For i = 2 To ListA_count
    key = ThisWorkbook.Worksheets("MatchUnMatch").Range("A" & i)

    For j = 1 To ListB_count
        cursor = ThisWorkbook.Worksheets("MatchUnMatch").Range("B" & j)
        'MsgBox "Key=" & Key & " Cursor=" & cursor
        If key = cursor Then
            ThisWorkbook.Worksheets("MatchUnMatch").Range("C" & k) = key
            k = k + 1
            Exit For
        End If
    Next j
Next i

'=======================================================================================================
'
'
' List 'A' items not in List 'B'
'
'
'=======================================================================================================
ListC_count = WorksheetFunction.CountA(ThisWorkbook.Worksheets("MatchUnmatch").Range("C:C"))

k = 2
For i = 2 To ListA_count
    key = ThisWorkbook.Worksheets("MatchUnMatch").Range("A" & i)
    flag = False
    For j = 1 To ListC_count
        cursor = ThisWorkbook.Worksheets("MatchUnMatch").Range("C" & j)
        If key = cursor Then
            flag = True
            Exit For
        End If
    Next j
    If flag = False Then
        ThisWorkbook.Worksheets("MatchUnMatch").Range("D" & k) = key
        k = k + 1
    End If
Next i

'=======================================================================================================
'
'
' List 'B' items not in List 'A'
'
'
'=======================================================================================================
k = 2

For i = 2 To ListB_count
    key = ThisWorkbook.Worksheets("MatchUnMatch").Range("B" & i)
    flag = False
    For j = 1 To ListC_count
        cursor = ThisWorkbook.Worksheets("MatchUnMatch").Range("C" & j)
        If key = cursor Then
            flag = True
            Exit For
        End If
    Next j
    If flag = False Then
        ThisWorkbook.Worksheets("MatchUnMatch").Range("E" & k) = key
        k = k + 1
    End If
Next i
End sub

see the image please, to understand what I mean我想在 A 行搜索 sheet(第一个 sheet)许多数字,然后我只想点击一次搜索按钮,这应该给我所有值都相同 time.I 不想多次点击一个搜索。 请有人帮我修好它。尽快:(

现在我完全理解了这个问题,我已经编辑了我的初始脚本。现在它在第一个 FIND 之后包含一个 FINDNEXT 循环,这将搜索 sheet 上的所有重复值。循环直到 FINDNEXT.cell.address 与 FIND.cell.address 相同。要仅在列 "A" 中搜索,我将 sheets(i).cells 更改为 sheets(i).Range("A:A") 在查找函数

 Sub find_cells()
Dim find_cell As Range
Dim colection_items As Collection
Dim look_up_value As String

nb_rows = Sheets(1).Cells(Rows.Count, 1).End(xlUp).Row  'count the number of rows with data on sheet(1)

Set colection_items = New Collection
For j = 2 To nb_rows
  colection_items.Add Sheets(1).Cells(j, 1).Value
Next j


counter_rows = 2 'the first row on sheet(2) where we start copying data from

For col = 1 To colection_items.Count

look_up_value = colection_items(col)
    For i = 2 To ThisWorkbook.Sheets.Count
    Sheets(i).Select
        Set find_cell = Sheets(i).Range("A:A").Find(What:=look_up_value, LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlRows, SearchDirection:=xlNext, MatchCase:=False)

           If Not find_cell Is Nothing Then
              Dim cell_adrs As String
              cell_adrs = find_cell.Address  'record address of the first instance of the lookup value on the sheet (i)
               Sheets(1).Cells(counter_rows, 1).Value = find_cell
               Sheets(1).Cells(counter_rows, 2).Value = find_cell.Offset(0, 1) 'copies data from the cell to the left by one column
               Sheets(1).Cells(counter_rows, 3).Value = find_cell.Offset(0, 2) 'copies data from the cell to the left by 2 columns
                'etc
               counter_rows = counter_rows + 1

                            Do
                                 Set find_cell = Sheets(i).Range("A:A").FindNext(find_cell)  'we lookup the next instance on sheet (i)
                                      If cell_adrs <> find_cell.Address Then    'if the next value found is different than the first value from sheet(i)
                                         Sheets(1).Cells(counter_rows, 1).Value = find_cell
                                         Sheets(1).Cells(counter_rows, 2).Value = find_cell.Offset(0, 1) 'copies data from the cell to the left by one column
                                         Sheets(1).Cells(counter_rows, 3).Value = find_cell.Offset(0, 2) 'copies data from the cell to the left by 2 columns
                                          counter_rows = counter_rows + 1
                                          'etc
                                      End If
                                Loop Until cell_adrs = find_cell.Address 'when all the values have been found and find_cell goes back to the first value
                            cell_adrs = Empty
            End If

    Next i
Next col
Sheets(1).Select
End Sub

(*) 在 OP 请求功能后更新,以保存以前运行的数据并且在 "data" sheet 中找不到数字标记为 "NOT FOUND"

(**) 在 OP 请求处理可变列数后更新

(***) 已更新以修复 FindItems() 函数以处理非连续单元格范围

(****) 已更新以修复 iRow sub Main()

中的更新

(*****) 更新为在 sheets 中搜索项目,其单元格 "A1" 的内容与 "base" sheets 的内容相同

(******) 更新为在所有数据 sheet 的 A 列中搜索项目,无论该列的 header 是什么

在我写代码的时候,Cornel 已经给了你一个不错的答案

无论你想管理什么:

  • 任何不同数量的 "data" 工作表(即:sheet 在其列 "A" 中查找项目编号并从相邻列收集相关数据)

  • 多次出现 "number" 在任何 "data" sheet

  • (*) 功能可保存先前运行"base" sheet 中已有的数据

  • (*) 在 "base" sheet 中标记 "NOT FOUND" 的功能,当在任何 "data" sheet[= 上找不到数字时14=]

  • (**) 处理可变列数的功能

那么你可能需要使用下面的代码

Option Explicit

Sub main()

Dim items() As Variant, itemToFind As Variant
Dim itemsNumber As Long, previousDataNumber As Long, dataShtNumber As Long, iRow As Long, i As Long, j As Integer
Dim itemsSht As Worksheet, dataShts() As Worksheet
Dim rngToCopy As Range
Dim itemFound As Boolean
Dim columnsNumberToCopyAndPaste As Long

columnsNumberToCopyAndPaste = 7 '<== here you set the number of columns to be copied form "data" sheet and pasted in "base" sheet

Set itemsSht = ThisWorkbook.Worksheets("Sheet1") ' this is the "base" sheet you take "numbers" from its column A, starting at row 2

Call GetItems(itemsSht, items(), itemsNumber, previousDataNumber) ' gather all "numbers" to be searched for in "data" sheets

Call GetDataWorksheets(dataShts(), ThisWorkbook, "Sheet1", dataShtNumber) ' gather all "data" sheets

iRow = 1
For i = 1 To itemsNumber 'loop through "numbers"

    itemToFind = items(i) ' "number" to be searched for in "data" sheets
    itemFound = False
    For j = 1 To dataShtNumber 'loop through "data" worksheets

        Set rngToCopy = FindItems(dataShts(j), itemToFind, 1, columnsNumberToCopyAndPaste) ' get "data" sheet column 1 cells with "number" along with 'columnsNumberToCopyAndPaste-1' adjacents cells

        If Not rngToCopy Is Nothing Then ' if found any occurrence of the "number" ...
            rngToCopy.Copy itemsSht.Cells(1, 1).Offset(previousDataNumber + iRow) ' ... copy it and paste into "base" sheet
            iRow = iRow + rngToCopy.Count / columnsNumberToCopyAndPaste 'update "base" sheet row offset to paste subsequent cells, if any
            itemFound = True
        End If

    Next j
    If Not itemFound Then 'if NOT found any occurrence of the "number" ...
        itemsSht.Cells(1, 1).Offset(previousDataNumber + iRow).Value = itemToFind
        itemsSht.Cells(1, 2).Offset(previousDataNumber + iRow).Resize(1, columnsNumberToCopyAndPaste - 1).Value = "NOT FOUND"
        iRow = iRow + 1
    End If

Next i

itemsSht.Columns.AutoFit

End Sub


Sub GetItems(itemsSht As Worksheet, items() As Variant, itemsNumber As Long, previousDataNumber As Long)

With itemsSht
    previousDataNumber = .Cells(.Rows.Count, 2).End(xlUp).Row - 1
    itemsNumber = .Cells(.Rows.Count, 1).End(xlUp).Row - 1 - previousDataNumber
    ReDim items(1 To itemsNumber) As Variant
    With .Cells(2 + previousDataNumber, 1).Resize(itemsNumber)
        If itemsNumber = 1 Then
            items(1) = .Value
        Else
            items = WorksheetFunction.Transpose(.Value)
        End If
    End With
End With

End Sub


Function FindItems(sht As Worksheet, itemToFind As Variant, columnToSearchFor As Long, columnsToCopy As Long) As Range
Dim cell As Range, unionRng As Range
Dim firstAddress As String

With sht.Columns(columnToSearchFor)
    Set cell = .Find(What:=itemToFind, LookAt:=xlWhole)
    If Not cell Is Nothing Then
        firstAddress = cell.Address
        Set unionRng = cell.Resize(, columnsToCopy)
        Do
            Set unionRng = Union(unionRng, cell.Resize(, columnsToCopy))

            Set cell = .FindNext(cell)
        Loop While Not cell Is Nothing And cell.Address <> firstAddress
        Set FindItems = unionRng
    End If
End With

End Function


Sub GetDataWorksheets(shts() As Worksheet, wb As Workbook, noShtName As String, nShts As Long)
Dim sht As Worksheet

For Each sht In wb.Worksheets
    With sht
        If .Name <> noShtName Then
            nShts = nShts + 1
            ReDim Preserve shts(1 To nShts) As Worksheet
            Set shts(nShts) = sht
        End If
    End With
Next sht

End Sub

(*) 实际上我添加了一个 previousDataNumber 变量来跟踪例程运行时已经存在的数据

(**) 在 columnsNumberToCopyAndPaste = 5 你设置要处理的列数

我将它拆分为一个 "main" 子和一些其他 "helper" 子或函数,以便有更清晰和更多的 maintainable/changeable 代码。

当我开始编写 looong subs 时,这个习惯对我的帮助总是超出我的预期