How to search for string in an array - arrays

Is there an easy (one-liner) to search for a string within an array in VBA? Or will I need to loop through each element and compare it with the target string?
EDIT:
It is a one-dimensional array. I only need to know IF a string is somewhere in the array.
IE:
names(JOHN, BOB, JAMES, PHLLIP)
How do I find out if "JOHN" is in the array, it needs to be minimal as it will be repeated around 5000 times and I don't want the function to slow the overall process down.

If you want to know if the string is found in the array at all, try this function:
Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = (UBound(Filter(arr, stringToBeFound)) > -1)
End Function
As SeanC points out, this must be a 1-D array.
Example:
Sub Test()
Dim arr As Variant
arr = Split("abc,def,ghi,jkl", ",")
Debug.Print IsInArray("ghi", arr)
End Sub
(Below code updated based on comment from HansUp)
If you want the index of the matching element in the array, try this:
Function IsInArray(stringToBeFound As String, arr As Variant) As Long
Dim i As Long
' default return value if value not found in array
IsInArray = -1
For i = LBound(arr) To UBound(arr)
If StrComp(stringToBeFound, arr(i), vbTextCompare) = 0 Then
IsInArray = i
Exit For
End If
Next i
End Function
This also assumes a 1-D array. Keep in mind LBound and UBound are zero-based so an index of 2 means the third element, not the second.
Example:
Sub Test()
Dim arr As Variant
arr = Split("abc,def,ghi,jkl", ",")
Debug.Print (IsInArray("ghi", arr) > -1)
End Sub
If you have a specific example in mind, please update your question with it, otherwise example code might not apply to your situation.

Another option would be use a dictionary instead of an array:
Dim oNames As Object
Set oNames = CreateObject("Scripting.Dictionary")
'You could if need be create this automatically from an existing Array
'The 1 is just a dummy value, we just want the names as keys
oNames.Add "JOHN", 1
oNames.Add "BOB", 1
oNames.Add "JAMES", 1
oNames.Add "PHILIP", 1
As this would then get you a one-liner of
oNames.Exists("JOHN")
The advantage a dictionary provides is exact matching over partial matching from Filter. Say if you have the original list of names in an Array, but were looking for "JO" or "PHIL" who were actually two new people in addition to the four we started with. In this case, Filter(oNAMES, "JO") will match "JOHN" which may not be desired. With a dictionary, it won't.

Another option that enforces exact matching (i.e. no partial matching) would be:
Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = Not IsError(Application.Match(stringToBeFound, arr, 0))
End Function
You can read more about the Match method and its arguments at
http://msdn.microsoft.com/en-us/library/office/ff835873(v=office.15).aspx

there is a function that will return an array of all the strings found.
Filter(sourcearray, match[, include[, compare]])
The sourcearray has to be 1 dimensional
The function will return all strings in the array that have the match string in them

Here's another answer. It works fast, reliably (see atomicules' answer) and has compact calling code:
' Returns true if item is in the array; false otherwise.
Function IsInArray(ar, item$) As Boolean
Dim delimiter$, list$
' Chr(7) is the ASCII 'Bell' Character.
' It was chosen for being unlikely to be found in a normal array.
delimiter = Chr(7)
' Create a list string containing all the items in the array separated by the delimiter.
list = delimiter & Join(ar, delimiter) & delimiter
IsInArray = InStr(list, delimiter & item & delimiter) > 0
End Function
Sample usage:
Sub test()
Debug.Print "Is 'A' in the list?", IsInArray(Split("A,B", ","), "A")
End Sub

more simple Function whichs works on Apple OS too:
Function isInArray(ByVal stringToBeFound As String, ByVal arr As Variant) As Boolean
Dim element
For Each element In arr
If element = stringToBeFound Then
isInArray = True
Exit Function
End If
Next element
End Function

This is my code, inspired by #atomicules
Public Function IsName(name As String) As Boolean
Dim names As Object
Set names = CreateObject("System.Collections.ArrayList")
names.Add "JOHN"
names.Add "BOB"
names.Add "JAMES"
names.Add "PHLLIP"
IsName = names.Contains(name)
End Function
And this is usage:
If IsName("JOHN") Then ...

You could use the following without the wrapper function, but it provides a nicer API:
Function IsInArray(ByVal findString as String, ByVal arrayToSearch as Variant) as Boolean
IsInArray = UBound(Filter(arrayToSearch,findString)) >= 0
End Function
The Filter function has the following signature:
Filter(sourceArray, stringToMatch, [Include As Boolean = True], [Compare as VbCompareMethod = vbBinaryCompare])

If it's a list of constants then you can use Select Case as follows:
Dim Item$: Item = "A"
Select Case Item
Case "A", "B", "C"
' If 'Item' is in the list then do something.
Case Else
' Otherwise do something else.
End Select

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

A Case statement might suit some applications more simply:
select case var
case "a string", "another string", sVar
'do something
case else
'do something else
end select

Related

Check for empty array indexes in VBA (that can include objects)

I need to do a is nothing check on a Variant array to exclude empty indexes from being used. I use is nothing to capture empty indexes which hold (empty) objects, it works fine but for indexes that hold regular data types (not objects), it throws an exception.
Dim arrArray() as Variant
'... fill array with values but leave some indexes out
'Loop through the array
For i = LBound(arrArray) To UBound(arrArray)
'Check if the current array item is an empty object
If arrArray(i) Is Nothing Then
'don't debug.print
'Debug if it's not an empty object
Else
Debug.Print arrArray(i)
End If
Next
I could use on error resume next but since error handling is done dynamically it would change the error handling status so I would like to avoid that. If it can't be avoided please check my other question.
Note: Currently I just work with empty objects, at some point in the future I might get an actual object. So in the long run I will have to check if the index contains an existing object (otherwise - I presume - debug.print will throw an error).
Please, try the next function. It will return a cleaned array (without empty elements) for a wide range of elements type:
Function elimEmptyArrayElements(arrX As Variant) As Variant
Dim i As Long, arrNoEmpty, k As Long
ReDim arrNoEmpty(UBound(arrX)): k = 0
For i = LBound(arrX) To UBound(arrX)
If Not IsMissing(arrX(i)) Then
If Not IsObject(arrX(i)) Then
If TypeName(arrX(i)) = "String" Then
If arrX(i) <> "" Then
arrNoEmpty(k) = arrX(i): k = k + 1
End If
Else
If Not IsEmpty(arrX(i)) Then
arrNoEmpty(k) = arrX(i): k = k + 1
End If
End If
Else
Set arrNoEmpty(k) = arrX(i): k = k + 1
End If
End If
Next i
ReDim Preserve arrNoEmpty(k - 1)
elimEmptyArrayElements = arrNoEmpty
End Function
Please, test it using the next Sub. It will stop on each pair of initial/cleaned array representation. When possible, both arrays are joined in Immediate Window.
If not possible, only the number of their elements (Ubound(arr)) is returned. You may iterate between each array elements and see that no empty one exists:
Sub testElimEmptyArrayElements()
Dim arr
arr = Split("1,7,9,,10,5,6,,2,8,3,4", ",")
Debug.Print Join(arr, "|") 'just to visually see the initial array content
arr = elimEmptyArrayElements(arr)
Debug.Print Join(arr, "|"): Stop 'the cleaned array
arr = Application.Transpose(Range("A2:A20").value) 'a 1D array extracted from a column range
Debug.Print Join(arr, "|")
arr = elimEmptyArrayElements(arr)
Debug.Print Join(arr, "|"): Stop 'the cleaned array
arr = Array(1, 2, 3, , 4, , 5): Debug.Print "Initial number of numeric elements: " & UBound(arr)
arr = elimEmptyArrayElements(arr): Debug.Print "Cleaned array number of numeric elements: " & UBound(arr): Stop
arr = Array(Range("A2"), Range("A3"), , Range("A6")): Debug.Print "Initial number of Range Object elements: " & UBound(arr)
arr = elimEmptyArrayElements(arr): Debug.Print "Cleaned array number of Range elements: " & UBound(arr): Stop
arr = Array(ActiveSheet, , ActiveSheet.Next): Debug.Print "Initial number of Sheet Object elements: " & UBound(arr)
arr = elimEmptyArrayElements(arr): Debug.Print "Cleaned array number of Sheet Object elements: " & UBound(arr): Stop
arr = Array("my string", 100, Range("A2"), , ActiveSheet, , ThisWorkbook, "test", 6): Debug.Print "Initial number of variate elements: " & UBound(arr)
arr = elimEmptyArrayElements(arr): Debug.Print "Cleaned array number of variate types elements: " & UBound(arr)
Debug.Print arr(2).value 'the cell value
Debug.Print arr(3).name 'the activesheet name
Debug.Print arr(4).Sheets.count 'activeworkbook number of sheets
End Sub
You can simply check and filter your array for empty slots with if YourArray(i)<>"" then syntax
Beside that, I see some wrong declaration issues in first line of your code:
1-You can't use Array as a name for your array
2-You should use parentheses after you array name (e.g. Dim myArray() as variant)
3-Variable type can not have parentheses (As far as I know)
I recommend to declare your array like following:
dim arr()
This way it automatically considered as an array of variants. So my suggested code would be like this:
Dim arr()
'... fill array with values but leave some indexes out
For i = LBound(arr) To UBound(arr)
If arr(i)<>"" Then
'do nothing
Else
'do something
end if
Next i

VBA check if whole row of multidimensional variant is empty without loops

Is there a quick way to check whether a whole row of a variant is empty?
My multi-dimensional array / variant has n-rows and m-columns.
The only way I can think of is to loop through the columns (of a specific row) and use the IsEmpty() function to determine if a cell is empty.
The variant only consists strings.
Do you know a faster way? Maybe something like this pseudo-code: IsEmpty(myarr(1,*))
this pseudocode would mean to check the all columns of the first row if they are empty.
You could try something like:
Sub Test()
Dim myarr() As Variant, indx As Long
myarr = Range("A8:C20").Value 'Or however you initialize your array.
indx = 1 'Or whichever row you would want to check.
With Application
Debug.Print Join(.Index(myarr, indx, 0), "") <> ""
End With
End Sub
Not sure if it will be faster than a loop though, since we call a worksheet application.
No, there isn't a faster way especially considering that arrays in VBA are stored column-wise in memory. The values on a single row are not stored adjacent in memory as it's the case with column values - you could easily test this by running a For Each loop on an array.
That being said, you should probably consider having a Function that checks if a specific row is empty so that you can call it repeatedly and maybe also check for null strings if needed. For example a range of formulas returning "" will not be empty but you might want to have the ability to consider them empty.
For example, you could use something like this:
Public Function Is2DArrayRowEmpty(ByRef arr As Variant _
, ByVal rowIndex As Long _
, Optional ByVal ignoreEmptyStrings As Boolean = False _
) As Boolean
Const methodName As String = "Is2DArrayRowEmpty"
'
If GetArrayDimsCount(arr) <> 2 Then
Err.Raise 5, methodName, "Array is not two-dimensional"
ElseIf rowIndex < LBound(arr, 1) Or rowIndex > UBound(arr, 1) Then
Err.Raise 5, methodName, "Row Index out of bounds"
End If
'
Dim j As Long
Dim v As Variant
'
For j = LBound(arr, 2) To UBound(arr, 2)
v = arr(rowIndex, j)
Select Case VBA.VarType(v)
Case VbVarType.vbEmpty
'Continue to next element
Case VbVarType.vbString
If Not ignoreEmptyStrings Then Exit Function
If LenB(v) > 0 Then Exit Function
Case Else
Exit Function
End Select
Next j
'
Is2DArrayRowEmpty = True 'If code reached this line then row is Empty
End Function
Public Function GetArrayDimsCount(ByRef arr As Variant) As Long
If Not IsArray(arr) Then Exit Function
'
Const MAX_DIMENSION As Long = 60
Dim dimension As Long
Dim tempBound As Long
'
'A zero-length array has 1 dimension! Ex. Array() returns (0 to -1)
On Error GoTo FinalDimension
For dimension = 1 To MAX_DIMENSION
tempBound = LBound(arr, dimension)
Next dimension
Exit Function
FinalDimension:
GetArrayDimsCount = dimension - 1
End Function
Notice that I haven't checked for IsObject as your values are coming from a range in Excel but you would normally check for that in a general case.
Your pseudocode IsEmpty(myarr(1,*)) could be translated to:
Is2DArrayRowEmpty(myarr, 1, False) 'Empty strings would not be considered Empty
or
Is2DArrayRowEmpty(myarr, 1, True) 'Empty strings would be considered Empty

VB6: Grabbing String Starting with x From an Array

Let's say I have the following Array, arr that contains a maximum of 20 substrings. In this example, the array will have 4 substrings:
arr = {"AAAA: 1234567" , "BBBB: 2345678" , "CCCC: 98765432" , "DDDD: 87654321"}
Note: Capitalization is not important.
I am needing assistance with finding a substring inside an array (again, up to 20 strings possible), that Starts With CCCC:, and then assigning that entire string to it's own variable, let's call it Var1.
I understand I could assign Var1 = arr(2), but I need to figure out how to determine the index number in the array that meets my criteria.
What I would really appreciate (although any method I will be happy with), is making a stand alone function such as:
Function ArrayIndex(ArrayInput as Variant, StartsWith as String) as Byte
'Arguments Here
End Function
Then I could just use this in my Subroutine:
Var1 = arr(ArrayIndex(arr, "CCCC:"))
Update 1
Here is a snippet of my current code
Sub T_Report
'<Shortcut = Shift+Ctrl+T>
Dim Data as String, DataArray as Variant
With ActiveSession
.Copy 0, 2, 80, 21 'Just a big block of text with multiple lines, copied to clipboard
Data = Clipboard 'Set Data to the clipboard value
DataArray = Split(Data,vbCrLf) 'This is "Data" in an Array, separated by line breaks
'Just checking to see if the Array was successful (it is)
Debug.Print DataArray(0) & vbNL & DataArray(1) & vbNL & DataArray(2) & _
vbNL & DataArray(3) & vbNL & DataArray(4) & vbNL & vbNL
'Misc code here
Dim sF1 as String, sF2 as String, sF3 as String
Dim Rslt1 as String, Rslt2 as String, Rslt3 as String
sF1 = "Field1:"
sF2 = "Field2:"
sF3 = "Field3:"
MsgBox DataArray(0) ' This works fine, giving me first substring
Rslt1 = FindMyString(sF1, DataArray)
' Misc Code
End With
End Sub
However, when I use the following function, I get Type Mismatch error on the MsgBox arr(0) line, although it should be giving me the very first substring of DataArray in the above sub (should be an exact match, the array has not been modified).. However, when I do MsgBox DataArray(0) above, I do get the first substring.
Private Function FindMyString(strToFind As String, ParamArray arr() As Variant) As String
Dim i As Integer
Dim iLen As Integer
Dim strArr As String
FindMyString = "" ' Returns Blank String if not found
' I get type mismatch here (Doesn't appear Array from sub loaded into this function)
MsgBox arr(0)
iLen = Len(strToFind)
For i = 0 To UBound(arr)
strArr = CStr(arr(i))
If strToFind = Left$(strArr, iLen) Then
FindMyString = strArr
Exit Function
End If
Next i
End Function
EDIT - FIX YOUR ARRAY LOAD
Change this (it MUST give you an error!):
arr = {"AAAA: 1234567" , "BBBB: 2345678" , "CCCC: 98765432" , "DDDD: 87654321"}
To This:
Dim arr As Variant
arr = Split("AAAA: 1234567,BBBB: 2345678,CCCC: 98765432,DDDD: 87654321", ",")
If you want to use a function to do your bidding you can pass an array of data using the ParamArray type. It has to be the last parameter in your function
This should do what you want:
Private Function FindMyString(strToFind as string, ParamArray arr() As Variant) As String
Dim i As Integer
Dim iLen as Integer
Dim strArr as String
FindMyString = "" ' Returns Blank String if not found '
Debug.Print arr(0)(0) ' Print first element of array
iLen = Len(strToFind)
For i = 0 To UBound(arr(0))
strArr = CStr(arr(0)(i))
If strToFind = Left$(strArr, iLen) Then
FindMyString = strArr
Exit Function
End If
Next i
End Function
In your example you can test it by:
Var1 = FindMyString("CCCC:", arr)

VBA - StrComp type mismatch or subscript out of range

I am running a For Loop to find a string inside a variant array. I am using StrComp to compare the strings. The array that I am using as the following format.
I have tried two approaches which I will describe bellow.
1st approach returns that the subscript is out of range when I use col=0
Function IsInArray(stringToBeFound As String, arr As Variant, col As Integer) As Long
Dim i As Long
' default return value if value not found in array
IsInArray = -1
For i = LBound(arr) To UBound(arr)
If StrComp(stringToBeFound, arr(i, col), vbTextCompare) = 0 Then
IsInArray = i
Exit For
End If
Next i
End Function
2nd approach tells me type mismatch at the StrComp
Function IsIn1DArray(stringToBeFound As String, arr As Variant) As Long
Dim i As Long
' default return value if value not found in array
IsIn1DArray = -1
For i = LBound(arr) To UBound(arr)
If StrComp(stringToBeFound, arr(i)) = 0 Then
IsIn1DArray = i
Exit For
End If
Next i
End Function
I have been using the IsInArray and IsIn1DArray in the past and works but not for this case. Imagine I would like to search for the string "[TestHeader]" and return its index. How would you do it?
arr is an array of arrays, so you need:
If StrComp(stringToBeFound, arr(i)(col), vbTextCompare) = 0 Then
Note this may fail for some values as your sub arrays are not the same size, so you should test the Ubound of the subarray first.
Function IsIn1dArray(stringToBeFound As String, arr As Variant) As Long
IsIn1dArray = Application.WorksheetFunction.Match(stringToBeFound, arr, 0)
End Function

Finding if a string is in a 2 dimensional VBA Excel array

I have a great function that I use all of the time for a 1 dimensional Excel VBA array that checks if a string is in an array:
Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = (UBound(Filter(arr(), stringToBeFound)) > -1)
End Function
Unfortunately it does not work when using it to check for a 2 dimensional array, like I have here:
Sub new_idea_filter()
home_sheet = ActiveSheet.Name
c = 1
Dim myfilters(1 To 4, 1 To 5000)
myfilters(1, 4) = "Test"
If IsInArray("Test", myfilters()) = True Then
killer = True
End If
End Sub
Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = (UBound(Filter(arr(), stringToBeFound)) > -1)
End Function
It keeps erroring out in the function saying subscript out of range, anyone have a thought how I can check if a string is in the 2 dimensional array?
Something from my code collection
You can use Application.Match. This will work for both 1D and 2D array :)
See this
Sub Sample()
Dim myfilters(1 To 4, 1 To 5000)
myfilters(1, 4) = "Test"
If IsInArray("Test", myfilters()) = True Then MsgBox "Found"
End Sub
Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
Dim bDimen As Byte, i As Long
On Error Resume Next
If IsError(UBound(arr, 2)) Then bDimen = 1 Else bDimen = 2
On Error GoTo 0
Select Case bDimen
Case 1
On Error Resume Next
IsInArray = Application.Match(stringToBeFound, arr, 0)
On Error GoTo 0
Case 2
For i = 1 To UBound(arr, 2)
On Error Resume Next
IsInArray = Application.Match(stringToBeFound, Application.Index(arr, , i), 0)
On Error GoTo 0
If IsInArray = True Then Exit For
Next
End Select
End Function
As long as you're in Excel (or have a reference to it), you can use the Index function to slice your array into rows or columns.
Public Function IsInArray(ByVal vToFind As Variant, vArr As Variant) As Boolean
Dim i As Long
Dim bReturn As Boolean
Dim vLine As Variant
For i = LBound(vArr, 1) To UBound(vArr, 1)
vLine = Application.WorksheetFunction.Index(vArr, i) 'slice off one line
If IsArray(vLine) Then 'if it's an array, use the filter
bReturn = UBound(Filter(vLine, vToFind)) > -1
Else 'if it's not an array, it was 1d so check the value
bReturn = vLine = vToFind
End If
If bReturn Then Exit For 'stop looking if one found
Next i
IsInArray = bReturn
End Function
Public Sub test()
Dim arr() As Variant
ReDim arr(1 To 2, 1 To 2)
arr(1, 2) = "Test"
Debug.Assert IsInArray("Test", arr)
arr(1, 2) = "Wrong"
Debug.Assert Not IsInArray("Test", arr)
ReDim arr(1 To 3)
arr(2) = "Test"
Debug.Assert IsInArray("Test", arr)
arr(2) = "Wrong"
Debug.Assert Not IsInArray("Test", arr)
Debug.Print "Passed"
End Sub
If you get the data from a recordset i use this method; first i use GetString for the recordset, second use Split to convert the string in a array unidimensional where each item is a string with all the information. After that you con use the function IsInArray.
The code is:
RecSet.Open strSQL, Cn
RecSet.MoveFirst
RecString = RecSet.GetString(, , ";", vbCr) 'genera una cadena con los datos. Campos separados por ; y registros por vbCR
RecSplit = Split(RecString, vbCr) 'Genera un array unidimensional con la cadena
you can test the code, but remember only works if you get the data from a recordset
You can try converting your original Function to be able to work with arrays. Please try the following, though note that I have not tested if it works.
Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
Dim cell As Variant
For Each cell In arr
IsInArray = IsInArray Or (UBound(Filter(cell(), stringToBeFound)) > -1)
Next
End Function
Regards
#Siddharth-Rout answer above is working perfectly with Application.Match in addition to the Filter function :-). - My solution tries to use the OP Filter function only: As the filter function needs a 1dim array, the array is splitted into portions.
A) Alternative solution using the original FILTER function instead of Match plus error handling
Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
Dim i As Long
If nDim(arr) = 1 Then
IsInArray = (UBound(Filter(arr(), stringToBeFound)) > -1)
Else ' allows using filter function in portions
For i = 1 To UBound(arr, 2)
If (UBound(Filter(Application.Transpose(Application.Index(arr, 0, i)), stringToBeFound)) > -1) Then IsInArray = True: Exit For
Next i
End If
End Function
Helper function to get array Dimension
Function nDim(ByVal vArray As Variant) As Long
' Purp: get number of array dimensions
' Site: http://support.microsoft.com/kb/152288
Dim dimnum As Long
Dim ErrorCheck As Variant
On Error GoTo FinalDimension
For dimnum = 1 To 60000
ErrorCheck = LBound(vArray, dimnum)
Next
FinalDimension:
nDim = dimnum - 1
End Function
B) Recursive solution using the original FILTER function instead of Match plus error handling
Function IsInArray(stringToBeFound As String, arr As Variant, Optional i As Long = 0) As Boolean
Select Case i
Case -1: ' stop 2dim calls
Case 0: IsInArray = IsInArray(stringToBeFound, arr, nDim(arr)) ' start recursive call
Case 1: IsInArray = (UBound(Filter(arr(), stringToBeFound)) > -1) ' 1dim array
Case Else ' allows using filter function in portions
If (UBound(Filter(Application.Transpose(Application.Index(arr, 0, i)), stringToBeFound)) > -1) Then
IsInArray = True
Else ' recursive calls (2dim array)
IsInArray = IsInArray(stringToBeFound, arr, IIf(i + 1 > UBound(arr), -1, i + 1))
End If
End Select
End Function
I have an Excel users version solution for this as well.
Cant you just split concatenate the array into a single column (1-d array)? you got x columns. who cares about the # of rows for now.
I would do : col 1 & "/// unique character delimiter"& col#1 & col 2 & "/// unique character delimiter"& col#2 & col 3 & "/// unique character delimiter"& col#2 & ... & & col (n-1) & "/// unique character delimiter"& col#(n-1) & & "/// unique character delimiter"& col#n
turning the 2-d array into a 1-d array.
and index match this joined-up array/column, to find the multiple occurances of the string located in the original array.
And whats good about this, because of the unique way you joined it (any unique delimator charavter + col# ) it can and will also tell you the original column each found return value of the string your looking for resided in. SO you dont loose any information.
(you can do that implementing =match ("/"&string&"/")) the position of the looked-for text in the lookup output and the next occurrence of the special unique delimiter & the next (subsequent) col # that's to the right of it.
Doesn't this do the same thing , as the macros above or the question asks for ?
and in an (almost) non-macro*/non-vba way?
*see below for why it can be done with out without macros.
So in the end, you can just turn any 2-d N.M array into an 1-d X array, while keeping all the information (of which column the text was originally belonging to) and still do a simple lookup, index-match or a LoopALL function (which is great) :
Lookupall macro to use to find and return multiple found occurrences of string:
Function LookupAll(vVal, rTable As Range, ColumnI As Long) As Variant
Dim rFound As Range, lLoop As Long
Dim strResults As String
With rTable.Columns(1)
Set rFound = .Cells(1, 1)
For lLoop = 1 To WorksheetFunction.CountIf(.Cells, vVal)
Set rFound = .Find(what:=vVal, After:=rFound, LookIn:=xlFormulas, lookAt _
:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:= _
False, SearchFormat:=False)
strResults = strResults & "," & rFound(1, ColumnI)
Next lLoop
End With
LookupAll = Trim(Right(strResults, Len(strResults) - 1))
End Function
Up to you whether you use VBA lookup all function above or an index-match formula in excel which can find and return multiple occurrences of a search find.
Delimation and join of separate columns of an array strips a need for an array search (which I've never been able to do as I wanted - ie. get the results all into 1 cell), and turns it into a single and simpler 1-d array without any information loss.
I believe the speed would be as fast (and accurate) as anything else. Particularly as you've reduced/condensed the array into a single array - 1 column.
Any thoughts?

Resources