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”.
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 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!
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
В данной статье показаны 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 оказывается немного быстрее.
Поиск относительного положения элемента в массиве (диапазоне) с помощью метода 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 |
I have declared an array containing 59 items as a string. Does anyone know how I could write a bit of code that would search another range (A:F), and highlight any cell that contained one of the items in my array yellow.
I think this might be a loop inside of another loop, but I am not sure how to construct it. Apologies for the lack of code, I hope the explanation is clear.
Thanks!
asked Aug 7, 2018 at 19:23
6
- Loop through the array
- Use Range.Find() method to find matching values (it returns a range)
- Highlight that returned range directly
Sub test()
Dim myArray As Variant
myArray = Array("a", "c", "d")
Dim word As Variant
For Each word In myArray
Sheet1.Range("A1:A11").Find(word).Interior.ColorIndex = 15
Next word
End Sub
After running this:
This is far superior than looping the entire range inside your array loop (or your looping your array loop inside your entire range loop) since the Range.Find()
method returns ONLY matches. Then we jsut highlight that range.
answered Aug 7, 2018 at 19:35
JNevillJNevill
45.8k3 gold badges36 silver badges60 bronze badges
6
For i = BeginningOfRange to EndOfRange
For j = LBound(Array) to UBound(Array)
If Cells(i, ReferenceColumn) = Array(j) Then
Cells(i, ReferenceColumn).Interior.ColorIndex = 6
End If
Next j
Next i
answered Aug 7, 2018 at 19:33
Here is a rough vba code that does that… Modify it to suit your needs
Sub highlightcells()
Dim arr(100) As Integer
For i = 0 To 58
arr(i) = i
Next i
Dim myrng As Range, cell As Range
Set myrng = Range("A1:B10")
For Each cell In myrng
For i = LBound(arr) To UBound(arr)
If cell.Value > 0 And cell.Value = arr(i) Then cell.Interior.Color = vbYellow
Next i
Next
End Sub
JNevill
45.8k3 gold badges36 silver badges60 bronze badges
answered Aug 7, 2018 at 19:43
diletant2 Пользователь Сообщений: 19 |
на лист в столбцы A:A и B:B импортированы два текстовых файла, представляющих собой отсортированные списки слов. из них формируются 2 массива:arr1 и arr2. требуется найти каждый из элементов второго массива arr2 в первом массиве arr1. 1) если элемент найден — он остается в массиве arr2 на своем месте; 2) если не найден — заменяется каким-нибудь текстом, например «ЯЯЯ». в конце измененный таким образом массив arr2 выгружается, на лист, например в тот же столбец B:B, дальше — сортируется. |
SuperCat Пользователь Сообщений: 2737 |
Ну вы файл-то приложите или мы тут гадать будем за вас? There is no knowledge that is not power |
diletant2 Пользователь Сообщений: 19 |
это что, ответ или вопрос? файла нет, да и нужен ли он? все просто:
2) второй столбец, он же массив arr2:
3) в результате работы макроса должно получиться arr2:
т.е. слова на своих местах, а те, что отсутствуют в arr1 — заменяем на ЯЯЯ |
Юрий М Модератор Сообщений: 60586 Контакты см. в профиле |
#4 13.12.2015 22:49:53
Так он у Вас уже на листе:
По второму вопросу возможны варианты: |
||||||
diletant2 Пользователь Сообщений: 19 |
Юрий М,, спасибо за ответ! 1. ну. сам-то список изначально в текстовом файле. его на лист еще надо взять, хотелось бы без лишних движений — сразу в массив, как? |
Юрий М Модератор Сообщений: 60586 Контакты см. в профиле |
1. Ну если выгрузить на лист, а потом удалить — разве не вариант? Мне кажется, это гораздо проще. |
diletant2 Пользователь Сообщений: 19 |
Юрий М, пример в 3-м комменте, куда еще примеристее? просто щас Ехеля под рукою нету его создавать, а что? |
Юрий М Модератор Сообщений: 60586 Контакты см. в профиле |
#8 13.12.2015 23:48:10
|
||||
Юрий М Модератор Сообщений: 60586 Контакты см. в профиле |
#9 13.12.2015 23:48:55
Как тогда проверите работу макроса? ) |
||
The_Prist Пользователь Сообщений: 14182 Профессиональная разработка приложений для MS Office |
#10 14.12.2015 00:01:05
Вот сами теперь возьмите, перепишите все это на лист Excel для незнакомого Вам человека, напишите под это код и распишите комментарии. Занятно, неправда? Особенно если учесть, что надо-то это больше всего Вам, а не нам. Никакой интересной задачи в Вашей проблеме нет.
В интернете есть справка по всем возможным вариантам циклов по массивам. MSDN называется. Куда еще комментаристее? Вы ленитесь приложить свои файлы TXT и файл Excel. Ни одной строки кода своей не привели для примера. А других просите расписать Вам все по полочкам? Да это какой халтурой попахивает. Надо Вам — а делать должны все другие?
А в голову не приходила мысль, что текстовый файл текстовому файлу рознь? И переписывать Ваших Вась и мам из сообщения в файл тоже мало кому охота для помощи Вам же. Поэтому никто не будет Вам коды тут полноценные с комментариями расписывать, когда никому не ясно как там данные вообще в текстовом файле разбиты.
P.S. Написан на коленке Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы… |
||||||||
diletant2 Пользователь Сообщений: 19 |
The_Prist, спасибо! исчерпывающе. насколько долго все это будет выполняться на массиве в млн. строк? |
Hugo Пользователь Сообщений: 23255 |
Так можно получить массив из текста не загружая его на лист: |
diletant2 Пользователь Сообщений: 19 |
#13 14.12.2015 14:01:28 спасибо за отзыв, Hugo!
попробовал применить к моим файлам — создать массив и потом его выгрузить на лист, так вот: весь массив почему-то состоит из одной первой строчки… |
||||
Юрий М Модератор Сообщений: 60586 Контакты см. в профиле |
#14 14.12.2015 14:14:46
Может пора этот файл показать? |
||||
diletant2 Пользователь Сообщений: 19 |
|
diletant2 Пользователь Сообщений: 19 |
#16 14.12.2015 14:33:31
такая же балалайка: весь массив только одна первая строчка… |
||
The_Prist Пользователь Сообщений: 14182 Профессиональная разработка приложений для MS Office |
#17 14.12.2015 14:40:52 Потому что
Попробуйте вместо vbNewLine использовать(каждый по очереди, а не все сразу): vbCr, vbLf, vbCrLf Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы… |
||
diletant2 Пользователь Сообщений: 19 |
|
diletant2 Пользователь Сообщений: 19 |
#19 15.12.2015 01:57:38
увы и ах: все три — выдают в массиве только первую строчку, что делать? |
||
Транспонировать массив. |
|
diletant2 Пользователь Сообщений: 19 |
#21 15.12.2015 04:00:56 Александр Моторин, спасибо за отзыв!
ОК, код можете дописать к уже предложенному:
|
||||
Как вставляешь массив на лист? |
|
Александр Моторин Пользователь Сообщений: 958 |
#23 15.12.2015 04:32:32
|
||
-=ArcheR=- Пользователь Сообщений: 60 |
diletant2
, такое ощущение что файла нет. Вы по типу людей из контрольной закупки ходите по площади магазина и просто примеряете все подряд не собираясь не чего покупать или взять незначительную мелочь. Люди для Вас посторались, а вы не соизволили даже выложить файл-пример, учитывая что Вас не однократно об этом просили разные люди, ВЫ их игнорите по какой то причине…… Не красиво. Задали вопрос из какого текстового документа выгружаются эти массивы. Так ответа и не увидели. |
diletant2 Пользователь Сообщений: 19 |
-=ArcheR=-,там миллион строк — Вам все предоставить? обычный словарь в столбик, отсортированный, там выше я выложил кусочек, в чем «врачебная ошибка»? Вы по существу можете что-то сказать? |
JayBhagavan Пользователь Сообщений: 11833 ПОЛ: МУЖСКОЙ | Win10x64, MSO2019x64 |
#26 15.12.2015 12:23:20
Ну, разве что в разделе работа -=ArcheR=- возьмётся за Ваше задание. Изменено: JayBhagavan — 15.12.2015 12:24:14 <#0> |
||||||
diletant2 Пользователь Сообщений: 19 |
JayBhagavan, это по существу? и так видно, что нечего сказать! |
diletant2 Пользователь Сообщений: 19 |
Кнопка цитирования не для ответа [МОДЕРАТОР] The_Prist, спасибо, код (из сообщения №10) работает, но очень медленно — часы, формулой ПОИСКПОЗ гораздо быстрее, правда потом проблема с сортировкой… Изменено: diletant2 — 15.12.2015 14:31:32 |
diletant2 Пользователь Сообщений: 19 |
#29 15.12.2015 14:28:14
спасибо, это работает, но на коротких файлах, на больших затыкается Run-time error ’13’: type mismatch, как обойти? |
||
Юрий М Модератор Сообщений: 60586 Контакты см. в профиле |
#30 15.12.2015 21:56:45 diletant2, я бы на Вашем месте извинился. В противном случае получите штраф или бан. |