33

I've got some code below, that is supposed to be checking if a value is in an Array or not.

Sub test()
    vars1 = Array("Examples")
    vars2 = Array("Example")
    If IsInArray(Range("A1").Value, vars1) Then
        x = 1
    End If

    If IsInArray(Range("A1").Value, vars2) Then
        x = 1
    End If
End Sub

Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
  IsInArray = (UBound(Filter(arr, stringToBeFound)) > -1)
End Function

If the cell A1 contains the word Examples for some reason both of the IsInArray detects it as existing for both Arrays when it should only find it existing in the vars1 array

What do I need to change to make my IsInArray function to make it an exact match?

Dan
  • 45,079
  • 17
  • 88
  • 157
Ryflex
  • 5,559
  • 25
  • 79
  • 148

8 Answers8

58

You can brute force it like this:

Public Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
    Dim i
    For i = LBound(arr) To UBound(arr)
        If arr(i) = stringToBeFound Then
            IsInArray = True
            Exit Function
        End If
    Next i
    IsInArray = False

End Function

Use like

IsInArray("example", Array("example", "someother text", "more things", "and another"))
Brad
  • 11,934
  • 4
  • 45
  • 73
  • 1
    Is there any benefits/negatives to using your method over changing the `IsInArray` function in my original code to use `IsInArray = Not IsError(Application.Match(stringToBeFound, arr, 0))` instead? – Ryflex Jul 08 '16 at 13:47
  • How big is your array? Is this more readable than the other methods? It might just be preference because iterating over an array is pretty quick, and (though I can't say for sure) the Match function is surely doing basically this. – Brad Jul 08 '16 at 13:49
  • I'm running 10~ arrays through `IsInArray`, in total all of them added up comes to 501 array items at the moment. It will eventually become bigger/more of them. – Ryflex Jul 08 '16 at 13:52
  • 3
    Those are small numbers. I'm not sure you'd see much of a difference either way. A third option is the `Dictionary` object. It has an `Exists` method and is easier to work with than arrays (no `ReDim Preserve` when adding items) – Brad Jul 08 '16 at 13:55
  • @Ryflex The biggest advantage is that it will not compare all of the elements like the other alternatives. My guess is that it can be a tiny bit slower than `Match` when the element is near the end of the array, but you can measure that with `Timer` to make sure. – Slai Aug 23 '16 at 11:39
  • 4
    @Ryflex @Slai it's maybe a bit late, but I wanted to clarify that using the `Match()` function is actually a lot slower than just iterating (looping) through the array. I did a test with an array of size 2000. The worst case scenario for looping through the array would be looking for the last item (at index 2000). After 5000 calls to both the `Match()` function and looping, the total time for `Match()` was `3.746094` but only `1.667969` for looping through the array. [Check the answer to this question for the code I used in my testing](https://stackoverflow.com/a/18769246/3023808) – Oscar Anthony Aug 29 '17 at 19:35
  • the following answer has a more powerful variant of this, because it also returns the index, if found: https://stackoverflow.com/a/52192798/1915920 – Andreas Covidiot May 27 '19 at 13:38
  • How to use with String arrays? – Banee Ishaque K Oct 08 '19 at 08:19
16

This Question was asked here: VBA Arrays - Check strict (not approximative) match

Sub test()
    vars1 = Array("Examples")
    vars2 = Array("Example")
    If IsInArray(Range("A1").value, vars1) Then
        x = 1
    End If

    If IsInArray(Range("A1").value, vars2) Then
        x = 1
    End If
End Sub

Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
    IsInArray = Not IsError(Application.Match(stringToBeFound, arr, 0))
End Function
Community
  • 1
  • 1
  • 1
    No need to loop through an array when it is done in excel, since excel have powerful match() function to do the comparison. – Sixthsense Jul 08 '16 at 13:45
  • 1
    @Sixthsense this doesn't loop through an array – ashleedawg Oct 10 '18 at 04:01
  • see the comment here regarding the performance issue with `Match` instead of *looping*: https://stackoverflow.com/questions/38267950/check-if-a-value-is-in-an-array-or-not-with-excel-vba#comment78852510_38268261 – Andreas Covidiot May 27 '19 at 13:36
8

I searched for this very question and when I saw the answers I ended up creating something different (because I favor less code over most other things most of the time) that should work in the vast majority of cases. Basically turn the array into a string with array elements separated by some delimiter character, and then wrap the search value in the delimiter character and pass through instr.

Function is_in_array(value As String, test_array) As Boolean
    If Not (IsArray(test_array)) Then Exit Function
    If InStr(1, "'" & Join(test_array, "'") & "'", "'" & value & "'") > 0 _
        Then is_in_array = True
End Function

And you'd execute the function like this:

test = is_in_array(1, array(1, 2, 3))
Sammy Douglas
  • 81
  • 1
  • 3
5

Use Match() function in excel VBA to check whether the value exists in an array.

Sub test()
    Dim x As Long

    vars1 = Array("Abc", "Xyz", "Examples")
    vars2 = Array("Def", "IJK", "MNO")

    If IsNumeric(Application.Match(Range("A1").Value, vars1, 0)) Then
        x = 1
    ElseIf IsNumeric(Application.Match(Range("A1").Value, vars2, 0)) Then
        x = 1
    End If

    MsgBox x
End Sub
Sixthsense
  • 1,927
  • 2
  • 16
  • 38
  • 4
    I changed the `IsInArray` function to use `IsInArray = Not IsError(Application.Match(stringToBeFound, arr, 0))` which resolves the problem – Ryflex Jul 08 '16 at 13:46
  • Not IsError() and IsNumeric() both results same answer when used with Match() function :) – Sixthsense Jul 08 '16 at 13:48
5

The below function returns '0' if there is no match and a 'positive integer' in case of matching:

Function IsInArray(stringToBeFound As String, arr As Variant) As Integer 
    IsInArray = InStr(Join(arr, ""), stringToBeFound) 
End Function

Note: the function first concatenates the entire array content to a string using 'Join' (not sure if the join method uses looping internally or not) and then checks for a match within this string using InStr.

jordanz
  • 367
  • 4
  • 12
  • would only works if `arr` items and `stringToBeFound` do not contain the `,` character/delimiter! – Andreas Covidiot May 27 '19 at 13:32
  • I tried it with ',' as well, but it still works! replaced 'Examples' with 'Exampl,es' in botb the arr and in stringToBeFound. Am i missing something? BTW, there was a typo in my code: now changed IsInArray = InStr(Join(arr, "), stringToBeFound) to IsInArray = InStr(Join(arr, ""), stringToBeFound) – Sreekumar Menon K Jun 05 '19 at 08:39
  • 2
    I meant "would only work ... reliably" ... `IsInArray( "ab", ("ab,c","d"))` would return `True`, but it should return `False` because none of the two array items `ab,c` nor `d` equals `ab`. Same for `IsInArray( "ab,c", ("ab","c"))` – Andreas Covidiot Jun 05 '19 at 09:12
2

I would like to provide another variant that should be both performant and powerful, because

...

'-1 if not found
'https://stackoverflow.com/a/56327647/1915920
Public Function IsInArray( _
  item As Variant, _
  arr As Variant, _
  Optional nthOccurrence As Long = 1 _
  ) As Long

    IsInArray = -1

    Dim i As Long:  For i = LBound(arr, 1) To UBound(arr, 1)
        If arr(i) = item Then
            If nthOccurrence > 1 Then
                nthOccurrence = nthOccurrence - 1
                GoTo continue
            End If
            IsInArray = i
            Exit Function
        End If
continue:
    Next i

End Function

use it like this:

Sub testInt()
  Debug.Print IsInArray(2, Array(1, 2, 3))  '=> 1
End Sub

Sub testString1()
  Debug.Print IsInArray("b", Array("a", "b", "c", "a"))  '=> 1
End Sub

Sub testString2()
  Debug.Print IsInArray("b", Array("a", "b", "c", "b"), 2)  '=> 3
End Sub

Sub testBool1()
  Debug.Print IsInArray(False, Array(True, False, True))  '=> 1
End Sub

Sub testBool2()
  Debug.Print IsInArray(True, Array(True, False, True), 2)  '=> 2
End Sub
Andreas Covidiot
  • 4,286
  • 5
  • 51
  • 96
1

While this is essentially just @Brad's answer again, I thought it might be worth including a slightly modified function which will return the index of the item you're searching for if it exists in the array. If the item is not in the array, it returns -1 instead.

The output of this can be checked just like the "in string" function, If InStr(...) > 0 Then, so I made a little test function below it as an example.

Option Explicit

Public Function IsInArrayIndex(stringToFind As String, arr As Variant) As Long

    IsInArrayIndex = -1

    Dim i As Long
    For i = LBound(arr, 1) To UBound(arr, 1)
        If arr(i) = stringToFind Then
            IsInArrayIndex = i
            Exit Function
        End If
    Next i

End Function

Sub test()

    Dim fruitArray As Variant
    fruitArray = Array("orange", "apple", "banana", "berry")

    Dim result As Long
    result = IsInArrayIndex("apple", fruitArray)

    If result >= 0 Then
        Debug.Print chr(34) & fruitArray(result) & chr(34) & " exists in array at index " & result
    Else
        Debug.Print "does not exist in array"
    End If

End Sub

Then I went a little overboard and fleshed out one for two dimensional arrays because when you generate an array based on a range it's generally in this form.

It returns a single dimension variant array with just two values, the two indices of the array used as an input (assuming the value is found). If the value is not found, it returns an array of (-1, -1).

Option Explicit

Public Function IsInArray2DIndex(stringToFind As String, arr As Variant) As Variant

    IsInArray2DIndex= Array(-1, -1)

    Dim i As Long
    Dim j As Long

    For i = LBound(arr, 1) To UBound(arr, 1)
        For j = LBound(arr, 2) To UBound(arr, 2)
            If arr(i, j) = stringToFind Then
                IsInArray2DIndex= Array(i, j)
                Exit Function
            End If
        Next j
    Next i

End Function

Here's a picture of the data that I set up for the test, followed by the test:

test 2

Sub test2()

    Dim fruitArray2D As Variant
    fruitArray2D = sheets("Sheet1").Range("A1:B2").value

    Dim result As Variant
    result = IsInArray2DIndex("apple", fruitArray2D)

    If result(0) >= 0 And result(1) >= 0 Then
        Debug.Print chr(34) & fruitArray2D(result(0), result(1)) & chr(34) & " exists in array at row: " & result(0) & ", col: " & result(1)
    Else
        Debug.Print "does not exist in array"
    End If

End Sub
Marcucciboy2
  • 3,156
  • 3
  • 20
  • 38
-1

You want to check whether Examples exists in Range("A1").Value If it fails then to check Example right? I think mycode will work perfect. Please check.

Sub test()
Dim string1 As String, string2 As String
string1 = "Examples"
string2 = "Example"
If InStr(1, Range("A1").Value, string1) > 0 Then
    x = 1
ElseIf InStr(1, Range("A1").Value, string2) > 0 Then
    x = 2
End If

End Sub

  • Yes, `Examples` exists in A1 and I can't use strings like you are using, I have an array for my code, otherwise I would have ordinaryly used `InStr` – Ryflex Jul 08 '16 at 13:42