Массивы vba excel поиск

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

Поиск относительного положения элемента в массиве (диапазоне) с помощью метода 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 оказывается немного быстрее.

 

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

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

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

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

 

marker_mc

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

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

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

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

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

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

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

 

Hugo

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

Сообщений: 23253
Регистрация: 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

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

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

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

 

Юрий М

Модератор

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

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

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

 

marker_mc

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

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

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

 

Hugo

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

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

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

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

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

 

Юрий М

Модератор

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

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

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

 

Hugo

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

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

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

 

nerv

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

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

#15

07.05.2013 23:33:39

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

с ADO (sql) проще

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

 

Hugo

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

Сообщений: 23253
Регистрация: 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

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

Сообщений: 23253
Регистрация: 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

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

Сообщений: 23253
Регистрация: 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

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

  • #2

can’t find anything — are you looping the values in the array — what code are you using to find a match…

something like:

Code:

n = 0
test = 10
Do Until n > z
    If varData(n) = test Then
        MsgBox "Match in Row " & n + 2
        Exit Sub
    End If
n = n + 1
Loop

(I had some code to create the array — z matches the number of values in the array)

  • #3

Yes, I’m using something very similar — just looping through the values and if I find a match I set a boolean variable to true and exit the loop. Its working fine — I was just wondering if there was a more efficient VBA function that does it in one line.

Anyway, thanks for the time…

Cheers,
Rajat

  • #4

Hi
If it’s a onedimensional array the Filter-Function could be used

dim z as variant
z = Filter(MyArray, Testvalue)
If UBound(z) < 0 Then MsgBox («empty»)

regards
Tommy

  • #5

Thanks Tommy, I wrote that out in one line (Ubound(filter….)), and now my code really does look slim. Great tip… thanks.

  • #6

Thanks for the tip Tommy.
However, I noticed that you need to be careful if passing a blank string as the search term.

Ordinarily, you’d expect a blank string to return false (that it does not exist in the array), unfortunately due to the way the filter function works, passing a blank string returns the entire array, which is then incorrectly reported as a successful search.

Instead consider the slight alteration:

Code:

[COLOR=Green]    'Initialise Array[/COLOR]
    [COLOR=RoyalBlue]Dim [/COLOR]myArray(2) [COLOR=RoyalBlue]As String[/COLOR]
    myArray(0) = "Value1"
    myArray(1) = "Value2"
    myArray(2) = "Value3"
    
   [COLOR=SeaGreen] 'Initialise Search Term[/COLOR]
    [COLOR=RoyalBlue]Dim [/COLOR]searchTerm [COLOR=RoyalBlue]As String[/COLOR]
    searchTerm = "Value2"
    
    [COLOR=SeaGreen]'Check if a value exists in the Array[/COLOR]
    [COLOR=RoyalBlue]If UBound[/COLOR](Filter(myArray, searchTerm)) >= 0 [COLOR=RoyalBlue]And [/COLOR]searchTerm <> ""[COLOR=RoyalBlue] Then[/COLOR]
        MsgBox ("Search Term SUCCESSFULLY located in the Array")
    [COLOR=RoyalBlue]Else[/COLOR]
        MsgBox ("Search Term could NOT be located in the Array")
    [COLOR=RoyalBlue]End If[/COLOR]

This works and corrects the issue of passing a blank string (this may be necessary if, for example, you are comparing the value a user typed into a cell against an array of valid values, within a manual validation function).

However, be aware that the Filter function also accepts partial matches.
For example, typing «Value» as the search term in the above example (with no number on the end) reports a valid match, even though no element in the array exactly matches this string.

Nevertheless, still should be a good one line alternative to using a loop and manually comparing each value in the array, assuming you can handle partial matches.

Last edited: Jun 26, 2011

  • #7

Here is a non-looping method that avoids the partial match problem that the Filter function opens one up to…

Code:

Dim C As String, FindMe As String, myArray() As Variant
Dim ItemFound As Boolean, MatchCase As Boolean
' Load dynamic Variant array in a single line of code
myArray = Array("Value1", "Value2", "Value3")
' Initialize search options
FindMe = "value2"
MatchCase = False
' Perform search
C = Chr$(1)
ItemFound = InStr(1, C & Join(myArray, C) & C, C & FindMe & C, 1 + MatchCase)
' Display result
If ItemFound Then
    MsgBox "Found it!"
Else
    MsgBox "Could NOT find it."
End If

The above code only finds whole array element matches; that is, if you searched for «Val», it would not match any elements in the array (the Filter function method would produce a match). I also provided a MatchCase Boolean variable to control whether the letter casing must be exact or not when performing the search.

  • #8

Simple Application.Match(value, array, 0) won’t help? That is if the array element you are searching for is exactly same — eg. looking for «john» will find «john» but not «john doe».

Don’t use WorkSheetFunction.Match, because when it doesn’t find a match, it will throw runtime error.

  • #9

Here is a non-looping method that avoids the partial match problem that the Filter function opens one up to…

Code:

Dim C As String, FindMe As String, myArray() As Variant
Dim ItemFound As Boolean, MatchCase As Boolean
' Load dynamic Variant array in a single line of code
myArray = Array("Value1", "Value2", "Value3")
' Initialize search options
FindMe = "value2"
MatchCase = False
' Perform search
C = Chr$(1)
ItemFound = InStr(1, C & Join(myArray, C) & C, C & FindMe & C, 1 + MatchCase)
' Display result
If ItemFound Then
    MsgBox "Found it!"
Else
    MsgBox "Could NOT find it."
End If

The above code only finds whole array element matches; that is, if you searched for «Val», it would not match any elements in the array (the Filter function method would produce a match). I also provided a MatchCase Boolean variable to control whether the letter casing must be exact or not when performing the search.

Isn’t calling it ‘non-looping’ misleading?
If InStr loop as I’d expect, ‘letter by letter’, then it’s actually a less efficient solution than the original. In the original you loop for as many elements as there are in the array, with InStr you are effectively loop for as many letters as there are in all of the elements combined.

It would be interesting to time this on an appropriately large data-set.

  • #10

Hello,
I have a problem in a macro. I have a function and function input is an array. I used another function in the function whhich I prepared before and input of this function coming from the main function. I code is given below. I don’t know how to pass input of one function to anaother function. Could you please help me.

Function G_TP(ParamArray Comp() As Variant) As Variant
G_TP = H_TP(Comp()) — Comp(0) * S_TP(Comp())
End Function

Comp() in the function H_TP() must be an array. But in this form only first term of the Comp() ig cominh to H_TP() other terms are not coming how can I solve it. Please help me.

Like this post? Please share to your friends:
  • Массивы vba excel описание
  • Массивы redim vba excel
  • Массивы excel с примерами
  • Массивы excel как создать
  • Массив ячеек excel это