Поиск элемента в массиве vba excel

In this Article

  • Searching in a One-Dimensional Array
    • Find values that match the Filter
    • Find values that DO NOT match the Filter
    • Case Sensitive Filters
    • Option Compare Text
  • Using a Loop to Search through an array
  • Searching in a Multi-Dimensional Array

This tutorial will demonstrate how to Search for (Find) a Value in an Array in VBA

There are a number of ways you can search for a string in an array – depending on whether the array is a one dimensional or multi-dimensional.

Searching in a One-Dimensional Array

To search for a value in a one-dimensional array, you can use the Filter Function.

Dim z As Variant
'filter the original array
  z = Filter(Array, String, True, vbCompareBinary)

The Syntax of the Filter option is a follows

Filter(Source Array, Match as String, [Include as Boolean], [Compare as vbCompareMethod])

The Source Array and the Match as String are required while the Include as Boolean and the Compare as vbCompareMethod are optional.  If these are not included they are set to True and vbCompareBinary respectively.

Find values that match the Filter

Sub FindBob()
   'Create Array
   Dim strName() As Variant
   strName() = Array("Bob Smith", "John Davies", "Fred Jones", "Steve Jenkins", "Bob Williams")
   
   'declare a variant to store the filter data in
   Dim strSubNames  As Variant

  'filter the original array
   strSubNames = Filter(strName, "Bob")

   'if you UBound value is greater than -1, then the value has been found
   If UBound(strSubNames ) > -1 Then MsgBox ("I found Bob")
End Sub

The second array will hold the values found by the filter.  If your UBound values are not -1, then the array has managed to find the  value that you were searching for.

You can also see how many times the text appears in the original array.

Sub CountNames()
   'Create array
   Dim strName() As Variant
   strName() = Array("Bob Smith", "John Davies", "Fred Jones", "Steve Jenkins", "Bob Williams")

  'declare an array to store the filter data in
   Dim strSubNames As Variant

   'filter the original array
   strSubNames = Filter(strName, "Bob")

   'if you add 1 to the UBound value, we will get the number of times the text appears
   Msgbox  UBound(strSubNames) + 1 & " names found." 
End Sub

Find values that DO NOT match the Filter

The [Include as Boolean] option allows you to find how many values in your array which DO NOT match your filter

Sub CountExtraNames() 
  'create array
  Dim strName() As Variant 
  strName() = Array("Bob Smith", "John Davies", "Fred Jones", "Steve Jenkins", "Bob Williams") 

  'declare an array to store the filter data in 
  Dim strSubNames As Variant 

  'filter the original array 
  strSubNames = Filter(strName, "Bob", False) 

  'if you add 1 to the UBound value, we will get the number of times the text appears 
  Msgbox  UBound(strSubNames) + 1 & " names found." 
End Sub

we have therefore amended this line:

strSubNames = Filter(strName, "Bob")

with this line:

strSubNames = Filter(strName, "Bob", False)

Using this line in the code, would return all the names that do NOT match “Bob”.

vba find array msgbox

Case Sensitive Filters

You will find that the filter is case sensitive by default.  This is true for all VBA functions.  If you want to search for text that is not case sensitive, you need to amend your code slightly.

z = Filter(strName, "bob",, vbTextCompare)

Adding vbTextCompare to your filter line will enable your code to find “bob” or “Bob”.  If this is omitted, VBA by default uses vbBinaryCompare which will only look for data that is an EXACT match.  Notice in the example above, we have left out the [Include as Boolean] argument so True is assumed.

Option Compare Text

Alternatively, you can add the text Option Compare Text to the top of your module – this will make all the functions that you write in that particular module case insensitive.

vba find array option compare text

VBA Coding Made Easy

Stop searching for VBA code online. Learn more about AutoMacro — A VBA Code Builder that allows beginners to code procedures from scratch with minimal coding knowledge and with many time-saving features for all users!

automacro

Learn More

Using a Loop to Search through an array

Using a loop is a little bit more complicated than using the Filter function.  We can create a function that will loop through all the values in the array.

Sub LoopThroughArray()
  'create array
  Dim strName() As Variant 
  strName() = Array("Bob Smith", "John Davies", "Fred Jones", "Steve Jenkins", "Bob Williams") 

Dim strFind as string 
strFind = "Bob"

Dim i As Long
'loop through the array
   For i = LBound(strName, 1) To UBound(strName, 1)
       If InStr(strName(i), strFind) > 0 Then
          MsgBox "Bob has been found!"
          Exit For
       End If
    Next i
End Sub

In order to find a part of the text string ie “Bob” instead of “Bob Smith” or “Bob Williams”, we needed to use the Instr Function in the If Statement.  This looked in the string returned by the loop from the Array to see if “Bob” was in the string, and as it was in the string, it would return a message box and then Exit the Loop.

Searching in a Multi-Dimensional Array

We also use the loop to search through a multi-dimensional array.  Once again, we need to create a function than enables us to loop through all the values in the array, but this time, we also need to loop through each dimension of the array.

Function LoopThroughArray()
   Dim varArray() As Variant
   Dim strFind As String
   strFind = "Doctor"
'declare the size of the array
   ReDim varArray(1, 2)
'initialise the array
   varArray(0, 0) = "Mel Smith"
   varArray(0, 1) = "Fred Buckle"
   varArray(0, 2) = "Jane Eyre"
   varArray(1, 0) = "Accountant"
   varArray(1, 1) = "Secretary"
   varArray(1, 2) = "Doctor"
'declare variables for the loop
   Dim i As Long, j As Long
'loop for the first dimension
   For i = LBound(varArray, 1) To UBound(varArray, 1)
'loop for the second dimension
      For j = LBound(varArray, 2) To UBound(varArray, 2)
'if we find the value, then msgbox to say that we have the value and exit the function
         If varArray(i, j) = strFind Then
            MsgBox "Doctor has been found!"
            Exit Function
         End If
      Next j
   Next i
End Function

Completing remark to Jimmy Pena’s accepted answer

As SeanC points out, this must be a 1-D array.

The following example call demonstrates that the IsInArray() function cannot be called only for 1-dim arrays,
but also for «flat» 2-dim arrays:

Sub TestIsInArray()
    Const SearchItem As String = "ghi"
    Debug.Print "SearchItem = '" & SearchItem & "'"
    '----
    'a) Test 1-dim array
    Dim Arr As Variant
    Arr = Split("abc,def,ghi,jkl", ",")
    Debug.Print "a) 1-dim array " & vbNewLine & "   " & Join(Arr, "|") & " ~~> " & IsInArray(SearchItem, Arr)
    '----
    
        '//quick tool to create a 2-dim 1-based array
        Dim v As Variant, vals As Variant                                       
        v = Array(Array("abc", "def", "dummy", "jkl", 5), _
                  Array("mno", "pqr", "stu", "ghi", "vwx"))
        v = Application.Index(v, 0, 0)  ' create 2-dim array (2 rows, 5 cols)
    
    'b) Test "flat" 2-dim arrays
    Debug.Print "b) ""flat"" 2-dim arrays "
    Dim i As Long
    For i = LBound(v) To UBound(v)
        'slice "flat" 2-dim arrays of one row each
        vals = Application.Index(v, i, 0)
        'check for findings
        Debug.Print Format(i, "   0"), Join(vals, "|") & " ~~> " & IsInArray(SearchItem, vals)
    Next i
End Sub
Function IsInArray(stringToBeFound As String, Arr As Variant) As Boolean
'Site: https://stackoverflow.com/questions/10951687/how-to-search-for-string-in-an-array/10952705
'Note: needs a "flat" array, not necessarily a 1-dimensioned array
  IsInArray = (UBound(Filter(Arr, stringToBeFound)) > -1)
End Function

Results in VB Editor’s immediate window

SearchItem = 'ghi'
a) 1-dim array 
   abc|def|ghi|jkl ~~> True
b) "flat" 2-dim arrays 
   1          abc|def|dummy|jkl|5         False
   2          mno|pqr|stu|ghi|vwx         True

 

marker_mc

Пользователь

Сообщений: 228
Регистрация: 24.12.2012

Всем добрый день.
Улучшаю себе один код и уперся в то, что тут правильно использовать массив array, но не могу понять как совершать поиск в массиве и батюшка гугл за 2 часа поиска мне ничем не помог. Находил что то типа Array.FindIndex — но vba ругается и не опознает что это вообще такое, справка про FindIndex тоже молчит.

есть 2 массива
b = Array(bol, glush, ivash, kov, kul, nest, shap, shitl)
m = Array(«a1», «a2», «a3», «a4», «a5», «a6», «a7», «a8» ;)

выбираю значение в combobox на userform, значения аналогичны значениям в массиве!
Подскажите пожалуйста, каким образом совершать поиск текста который вернул комбобокс в массиве b?

на словах звучит так:
Combobox1.Text найти какой по счету в массиве b и вернуть значение с найденным индексом с массива m

Заранее спасибо!

Изменено: marker_mc07.05.2013 14:58:12

 

LVL

Пользователь

Сообщений: 903
Регистрация: 01.01.1970

Перебор всех значений в цикле или словарь  ;)

 

marker_mc

Пользователь

Сообщений: 228
Регистрация: 24.12.2012

я только к массивам добрался, а вы меня словарём сразу)))))
И насчет перебора циклом, каким образом это делать? как пользоваться for … next я знаю, но как по array шерстить?

 

marker_mc

Пользователь

Сообщений: 228
Регистрация: 24.12.2012

#4

07.05.2013 15:41:44

вопрос снят! LVL, спасибо за наводку. Сделал перебор значений в массиве через For Next

Выглядит так:

Код
        For i = 0 To 7
            If ComboBox1.Text= m(i) Then
                iBook = b(i)
                Exit For
            End If
        Next i
 

Hugo

Пользователь

Сообщений: 23255
Регистрация: 22.12.2012

Комбобокс? Используйте индекс (т.е. номер выбранной записи).
Был бы пример в файле… :)

 

marker_mc

Пользователь

Сообщений: 228
Регистрация: 24.12.2012

Hugo, я правильно понял, что можно вернуть номер значения по счету из комбобокс?

Если правильно понимаю, то вы предлагаете вернуть этот номер и найти значение по номеру в array
Вариант неплохой и судя по всему исключает перебор, но это только в том случае если сортировка комбобокса совпадает с размещением данных в array, но если этот порядок будет разным, то соответственно получим не тот результат что ожидаем.

Но все таки интересно на будущее, каким образом получить этот индекс?

Насчет файла… признаю честно, специально не стал ложить сюда, чтоб не дали готового решения! Хотелось именно пару наводок, чтоб самому дойди… мне полезно, я учусь)))))

Изменено: marker_mc07.05.2013 15:55:23

 

Hugo

Пользователь

Сообщений: 23255
Регистрация: 22.12.2012

#7

07.05.2013 15:58:52

Ну Вы же сказали, что в комбобоксе то, что и в массиве. Т.е. возможно массив является источником комбобокса… А примера нет…

Код
Private Sub ComboBox1_Change()
MsgBox ComboBox1.ListIndex
End Sub

Начало нумерации с 0.

Изменено: Hugo07.05.2013 16:02:16

 

marker_mc

Пользователь

Сообщений: 228
Регистрация: 24.12.2012

#8

07.05.2013 16:05:57

Цитата
Hugo пишет:
А примера нет…
Цитата
marker_mc пишет:
Насчет файла… признаю честно, специально не стал ложить сюда, чтоб не дали готового решения! Хотелось именно пару наводок, чтоб самому дойди… мне полезно, я учусь)))))

))))

Да, в КБ тоже что и в Массиве и расположение тоже такое же, но КБ формируется не с массива, а с именованного диапазона EXCEL… но я немножко забегая на будущее… по принципу «а мало ли….» во избежании ошибки.
за ListIndex спасибо, запомню что такое тоже есть… и при условии когда массив и КБ идентичны это будет поудобнее чем перебор.

Спасибо за подсказки!

 

Hugo

Пользователь

Сообщений: 23255
Регистрация: 22.12.2012

Ну если с листа — то можно на листе формулой поискать.

 

Юрий М

Модератор

Сообщений: 60586
Регистрация: 14.09.2012

Контакты см. в профиле

на лист можно и Find натравить.

 

marker_mc

Пользователь

Сообщений: 228
Регистрация: 24.12.2012

Ребята, поиск на листе это Вы уже не туда пошли… .find это я уже прошел и пользуюсь… стоял вопрос именно в массиве VBA  array который с листом никак не связан, а вот КБ формируется именно с листа через созданное имя в диспетчере имен.
Но вопрос уже был решен… я применил по наводке LVL именно перебор.
ListIndex от Hugo тоже интересно, но при условии что данные КБ идентичны расположению данных в array.
И эти два способа полностью подходят. Если уже крутить немного тему дальше… LVL предложил еще вариант через словарь… было бы интересно как с ним работать, потому что до него еще не добирался и пока что не знаю с чем его едят.

 

Hugo

Пользователь

Сообщений: 23255
Регистрация: 22.12.2012

Да словарей тут вагон был…
Ищите по scripting.dictionary
Смысл такой — запоминаем в словаре слово и к нему ещё что-то (номер, массив, другой словарь… В данном случае номер).
Далее в любой момент обращаемся к словарю и по слову берём номер (ну или что там запомнили…) И то, что запомнили — можно в любой момент изменить.

Хотя конечно на 8 значений нет смысла словарь привлекать (тем более что искать нужно только 1 значение при каждом запуске кода) — оставляйте перебор.
Словарь нужен когда нужно найти например 10000 пар в двух несортированных списках, ну или подсчитать количество повторов уникальных.

Изменено: Hugo07.05.2013 23:27:13

 

Юрий М

Модератор

Сообщений: 60586
Регистрация: 14.09.2012

Контакты см. в профиле

Куда-то мой пост подевался)))

 

Hugo

Пользователь

Сообщений: 23255
Регистрация: 22.12.2012

Сапожник без сапог :)
Что стережём, то и имеем :)

 

nerv

Пользователь

Сообщений: 3071
Регистрация: 22.12.2012

#15

07.05.2013 23:33:39

Цитата
Hugo пишет:
Словарь нужен когда нужно найти например 10000 пар в двух несортированных списках, ну или подсчитать количество повторов уникальных

с ADO (sql) проще

Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина — самый громкий звук
https://github.com/nervgh

 

Hugo

Пользователь

Сообщений: 23255
Регистрация: 22.12.2012

Но дольше :)
С ADO проще, когда есть класс от nerv или Function ADO_R_Dmitry() :)
Но ведь есть строгие требования к данным. А с словарём простор для манёвра.

 

nerv

Пользователь

Сообщений: 3071
Регистрация: 22.12.2012

#17

08.05.2013 00:38:24

Цитата
Hugo пишет:
Но дольше

не понял

Цитата
Hugo пишет:
С ADO проще, когда есть класс от nerv или Function ADO_R_Dmitry()

ну, так зачем много раз одно и тоже набирать, если можно один раз сделать и потом использовать? Обычная практика. Всю лишнюю/скучную/глупую рутинную работу переложить на класс/функцию.

Цитата
Hugo пишет:
А с словарём простор для манёвра.

пример маневра

Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина — самый громкий звук
https://github.com/nervgh

 

Hugo

Пользователь

Сообщений: 23255
Регистрация: 22.12.2012

Я как-то сравнивал скорость работы — словарь был быстрее. Можем ещё на какой задаче проверить.
Ну а пример маневра — например в столбце числа тестом, или даты не даты, или нужно отбирать только те строки, где есть определённый текст, ну или ещё другие «или»…
Насчёт рутины — в общем со словарями аналогично, часто можно с небольшими коррекциями использовать один уже написанный код :)

 

ambasad

Пользователь

Сообщений: 26
Регистрация: 01.01.1970

#19

08.05.2013 11:18:17

Цитата
marker_mc пишет:
стоял вопрос именно в массиве VBAarray который с листом никак не связан, а вот КБ формируется именно с листа через созданное имя в диспетчере имен.

Может имеет смысл заполнить массив с того же листа? тогда всё будет совпадать

 

Слэн

Пользователь

Сообщений: 5192
Регистрация: 16.01.2013

WorksheetFunction.Match() вам в помощь, но находит не индекс массива, а номер начиная с единицы. если индекс тоже с единицы, то все ок, иначе надо корректировать..

 

nerv

Пользователь

Сообщений: 3071
Регистрация: 22.12.2012

#21

08.05.2013 13:21:04

Цитата
Hugo пишет:
Я как-то сравнивал скорость работы — словарь был быстрее.

я почему то сомневаюсь )

Цитата
Hugo пишет:
Ну а пример маневра — например в столбце числа тестом, или даты не даты, или нужно отбирать только те строки, где есть определённый текст, ну или ещё другие «или»…

все вышеописанное можно сделать с помощью ADO (SQL)

Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина — самый громкий звук
https://github.com/nervgh

 

ikki

Пользователь

Сообщений: 9709
Регистрация: 22.12.2012

#22

08.05.2013 13:31:32

Цитата
nerv пишет:  я почему то сомневаюсь

а что мешает потестировать?  :)
я несколько раз сравнивал (для простых SQL-запрсов, без вычислений для каждой строчки) — SQL медленнее примерно в три раза.

фрилансер Excel, VBA — контакты в профиле
«Совершенствоваться не обязательно. Выживание — дело добровольное.» Э.Деминг

 

marker_mc

Пользователь

Сообщений: 228
Регистрация: 24.12.2012

Раз уж тема крутится дальше…
мне как вариант еще понравилось предложение ambasad, внести данные в массив с листа.
как записать в array именованный диапазон?
вместо этого
b = Array(bol, glush, ivash, kov, kul, nest, shap, shitl)

что то типа такого можно?

b = Array([именованный диапазон])

 

LVL

Пользователь

Сообщений: 903
Регистрация: 01.01.1970

#24

08.05.2013 13:41:32

Код
b=range("XXX").value

b — динамический массив типа Variant
XXX — название именованого диапазона  ;)

 

marker_mc

Пользователь

Сообщений: 228
Регистрация: 24.12.2012

LVL, это будет тогда не массив, а просто диапазон судя по записи

 

Hugo

Пользователь

Сообщений: 23255
Регистрация: 22.12.2012

a = [именованный_диапазон].Value

Но получите двумерный массив.

 

marker_mc

Пользователь

Сообщений: 228
Регистрация: 24.12.2012

но а записать в переменную как
Dim a() ???
это и будет обозначения того что это array?

 

LVL

Пользователь

Сообщений: 903
Регистрация: 01.01.1970

 

LVL

Пользователь

Сообщений: 903
Регистрация: 01.01.1970

в какую переменную? Массив и есть переменная  ;)

 

marker_mc

Пользователь

Сообщений: 228
Регистрация: 24.12.2012

#30

08.05.2013 13:45:57

Ок, попробую ради интереса еще так переделать. Спасибо. Хотя через цикл уже давно работает))))

Поиск относительного положения элемента в массиве (диапазоне) с помощью метода VBA Excel WorksheetFunction.Match. Синтаксис, параметры, примеры.

WorksheetFunction.Match – это метод VBA Excel, который возвращает относительное положение элемента в массиве (диапазоне), соответствующее его порядковому номеру в массиве (диапазоне). Метод соответствует функции рабочего листа =ПОИСКПОЗ (поиск позиции).

Обратите внимание на то, что

  • поиск позиции в массиве возможен, если он одномерный или двумерный, но с набором элементов только по одному измерению, например: myArray(8, 0) или myArray(1 To 1, 1 To 20);
  • поиск позиции в диапазоне рабочего листа возможен, если он содержит только одну строку или один столбец;
  • нумерация относительного положения элемента в массиве начинается с единицы, независимо от заданной индексации массива.

Синтаксис

Синтаксис метода WorksheetFunction.Match в VBA Excel:

WorksheetFunction.Match (Arg1, Arg2, [Arg3])

Параметры

Описание параметров метода WorksheetFunction.Match:

Параметр Описание
Arg1 Обязательный параметр. Значение элемента массива, по которому будет произведен поиск относительного положения элемента в массиве.
Arg2 Обязательный параметр. Непрерывный диапазон ячеек или массив, в котором будет произведен поиск позиции элемента, значение которого совпадет со значением параметра Arg1.
Arg3 Необязательный параметр. Задает тип сопоставления значения Arg1 со значениями в массиве Arg2.

В параметре Arg1 можно использовать знаки подстановки для шаблонов, те же, что и для методов Find и Replace.

Значения параметра Arg3, задающие тип сопоставления:

Значение Тип сопоставления
-1 Метод WorksheetFunction.Match находит наименьшее значение элемента в Arg2, большее или равное Arg1. Значения элементов Arg2 должны быть расположены в убывающем порядке: [m, … 2, 1, 0, -1, -2, … -n], [z – a], [True, False] и т. д.
0 Метод WorksheetFunction.Match находит в Arg2 первое значение, равное Arg1. Значения элементов Arg2 могут быть расположены в любом порядке.
1 Значение по умолчанию. Метод WorksheetFunction.Match находит наибольшее значение элемента в Arg2, меньшее или равное Arg1. Значения элементов Arg2 должны быть расположены в возрастающем порядке: [-n, … -2, -1, 0, 1, 2, … m], [a – z], [False, True] и т. д.

При сопоставлении строк регистр не учитывается.

Примеры

Пример 1

Поиск относительного положения элемента в массиве, индексация которого начинается с нуля:

Sub Primer1()

Dim myArray As Variant, n As Long

‘заполнение массива значениями, нумерация элементов массива начинается с нуля

myArray = Array(«Арка», 45, «Дуб», «Клуб», 85.37, «Литр», 103, «Небо», «Столб»)

‘определяем относительное положение элемента в массиве, при чем

‘нумерация относительного положения начинается с единицы

n = WorksheetFunction.Match(«Клуб», myArray)

MsgBox n ‘Результат: 4

MsgBox myArray(n) ‘Результат: 85.37, так как нумерация массива начинается с нуля

End Sub

Пример 2

Определение индекса элемента в массиве по его относительному положению, возвращенному методом WorksheetFunction.Match:

Sub Primer2()

Dim myArray(7 To 15) As Variant, i As Long, n As Long

    ‘заполнение элементов массива значениями

    For i = 7 To 15

        myArray(i) = Choose(i, «», «», «», «», «», «», «Арка», 45, «Дуб», «Клуб», 85.37, «Литр», 103, «Небо», «Столб»)

    Next

n = WorksheetFunction.Match(«Клуб», myArray)

MsgBox n ‘Результат: 4

‘находим индекс элемента в массиве по его относительному положению

n = n + LBound(myArray) 1

MsgBox myArray(n) ‘Результат: Клуб

End Sub

Пример 3

Определение адреса ячейки на рабочем листе по найденному методом WorksheetFunction.Match относительному положению этой ячейки в заданном диапазоне:

Sub Primer3()

Dim n As Long

n = WorksheetFunction.Match(«Брелок», Range(«B1400:B1410»), 0)

    With Range(«B1400:B1410»)

        MsgBox «Значение = « & .Cells(n) & vbNewLine & _

        «Адрес = « & .Cells(n).Address & vbNewLine & _

        «Строка = « & .Cells(n).Row & vbNewLine & _

        «Столбец = « & .Cells(n).Column

    End With

End Sub


В данной статье показаны 2 способа быстрого поиска значений в двумерных массивах.

Поскольку искомое значение может встретиться в нескольких строках обрабатываемого двумерного массива,

оба способа получают на выходе отфильтрованный двумерный массив.

Способы формирования отфильтрованных массивов — разные:

первый способ использует функцию ArrAutofilterEx

второй способ — функцию ArraySearchResults

Основные отличия и особенности этих 2 способов поиска:

  • ArrAutofilterEx позволяет задавать несколько критериев поиска (фильтрации)
  • ArrAutofilterEx ищет вхождение искомого текста в значения заданных столбцов (неточное совпадение)
  • ArrAutofilterEx при каждом вызове заново в цикле перебирает все элементы массива,
    соответственно, при поиске 10 значений время работы кода увеличивается в 10 раз
  • ArraySearchResults позволяет использовать фильтрацию массива только по одному столбцу
  • ArraySearchResults ищет совпадение искомого текста со значением столбца (точное совпадение)
  • ArraySearchResults производит поиск в заранее сформированной текстовой строке
    Таким образом, перебираются все ячейки массива в цикле только один раз, и поиск 100 значений в массиве займёт ненамного больше времени, чем поиск 1 значения.

Примеры поиска в огромных массивах:

Поиск с использованием ArrAutofilterEx

Sub ПримерМедленногоПоискаВМассиве()
    t = Timer
    ИскомоеЗначение$ = 560
    СтолбецДляПоиска& = 3
 
    ' загружаем массив с листа
    arr = [a1:d30000].Value
 
    ' укорачиваем массив Arr, оставляя лишь те строки,
    ' где в заданном столбце есть искомое значение
    On Error Resume Next: Err.Clear
    resArr = ArrAutofilterEx(arr, СтолбецДляПоиска& & "=" & ИскомоеЗначение$)
 
    ' проверяем возвращеное функцией значение на наличие результатов поиска
    If Err Then Debug.Print "Такие строки в массиве не найдены": Exit Sub
 
    ' выводим из отфильтрованных строк значения первого столбца
    For i = LBound(resArr) To UBound(resArr)
        Debug.Print "Результат - строка " & i & " из " & UBound(resArr) & ": ", resArr(i, 1)
    Next i
    Debug.Print "Время: " & Timer - t & " сек."
End Sub

Поиск с использованием ArraySearchResults

Sub ПримерБыстрогоПоискаВМассиве()
    t = Timer
    ИскомоеЗначение$ = 560
    СтолбецДляПоиска& = 3
 
    ' загружаем массив с листа
    arr = [a1:d30000].Value
 
    ' формируем строку поиска
    ss$ = SearchString(arr, СтолбецДляПоиска&)
 
    ' укорачиваем массив Arr, оставляя лишь те строки,
    ' где в заданном столбце есть искомое значение
    resArr = ArraySearchResults(arr, ss$, ИскомоеЗначение$)
 
    ' проверяем возвращеное функцией значение на наличие результатов поиска
    If Not IsArray(resArr) Then Debug.Print "Такие строки в массиве не найдены": Exit Sub
 
    ' выводим из отфильтрованных строк значения первого столбца
    For i = LBound(resArr) To UBound(resArr)
        Debug.Print "Результат - строка " & i & " из " & UBound(resArr) & ": ", resArr(i, 1)
    Next i
    Debug.Print "Время: " & Timer - t & " сек."
End Sub

Код функции ArraySearchResults:

Function ArraySearchResults(ByRef arr, ByRef searchStr As String, ByVal txt As String, _
                            Optional ByVal Sep As String = "%$%") As Variant
    ' функция получает в качестве параметров массив Arr,
    ' и заранее сформированную строку SearchString из значений ячеек нужного столбца массива
    ' По этой строке SearchString функция ищет строки массива, в которые встречается значение txt,
    ' и возвращает усечённый массив, содержащий только подходящие строки
    ' Поиск ведётся по ТОЧНОМУ совпадению значений

    ro& = 0: spl = Split(searchStr, Sep & txt & Sep)
    If UBound(spl) = 0 Then Exit Function    ' нет в массиве нужных строк
    ' перебираем результаты поиска, вычисляя номера строк в исходном массиве
    For i = LBound(spl) To UBound(spl) - 1
        txt = spl(i): ro& = ro& + 1 + (Len(spl(i)) - Len(Replace(spl(i), Sep, ""))) / Len(Sep)  2
        spl(i) = ro&
    Next i
    ' подготавливаем массив для результатов:
    ' по ширине - как исходный, по высоте - содержащий столько строк, сколько найдено совпадений
    ReDim resArr(1 To UBound(spl), LBound(arr, 2) To UBound(arr, 2))
    ' заполняем новый массив
    For i = LBound(spl) To UBound(spl) - 1
        For j = LBound(arr, 2) To UBound(arr, 2)
            resArr(i + 1, j) = arr(spl(i), j)
        Next j
    Next i
    ArraySearchResults = resArr
End Function
 
Function SearchString(ByRef arr, ByVal ArrayColumn As Long, _
                      Optional ByVal Sep As String = "%$%") As String
    ' Объединяет все значения из столбца ArrayColumn массива Arr в одну текстовую строку,
    ' в качестве разделителя элементов используя строку Sep
    ' Для ускорения конкатенации длинных строк используются
    ' промежуточные переменные buffer$ и buffer2$
    buffer$ = "": buffer2$ = "": Sep2$ = Sep$ & Sep$: Const BufferLen& = 6000
    On Error Resume Next: Err.Clear: SearchString = Sep2$
    If ArrayColumn > UBound(arr, 2) Or ArrayColumn < LBound(arr, 2) Then Exit Function
    For i = LBound(arr) To UBound(arr)
        buffer$ = buffer$ & Trim$(arr(i, ArrayColumn)) & Sep2$
        If Len(buffer$) > BufferLen& Then
            buffer2$ = buffer2$ & buffer$: buffer$ = ""
            If Len(buffer2$) > BufferLen& * 20 Then _
               SearchString = SearchString & buffer2$: buffer2$ = ""
        End If
    Next i
    SearchString = SearchString & buffer2$ & buffer$
End Function

При поиске только одного значения время работы обоих макросов поиска не сильно отличается — но обычно функция ArraySearchResults оказывается немного быстрее.

Понравилась статья? Поделить с друзьями:
  • Поиск ячеек с ошибками в excel
  • Поиск экстремума функции excel
  • Поиск ячеек с определенным значением в excel
  • Поиск шрифта в word
  • Поиск ячеек в которых нет символа excel