Passing String of arrays through a function in VBA - arrays

I am creating several string arrays and attempting to use a function for each array on an excel sheet. It is supposed to go through each row and every row it counts to see if any of the strings match with the value in the currently active cell. I seem to get and error when i try to pass the string array to the function and get an empty value for the function parameter. Here is my code
the array
anArray = Array("string1", "string2", "string3")
the function
Function checkArray(a as Variant) as integer
Range("A1")
Dim count As Integer
count = a.Length - 1
Do While ActiveCell.Value <> ""
Do While count <> -1
If ActiveCell.Value = a(count) Then
checkArray = checkArray + 1
End If
count = count -1
Next i
ActiveCell.Offset(1, 0).Select
Loop
End Function
and i call it
checkArray(anArray)

There seems to be a few necessary things missing from your sample function code.
Functions cannot select cells to process them but you can pass a range of one or more cells into the function as a parameter to be processed.
You've described your array using VBA code but made no mention as to how the function is supposed to determine the nature of the array beyond being fed it as an incoming parameter. This conflicts with teh nature of the remainder of the sample function code since it looks like it is to be used as a UDf worksheet function.
Here is what I would expect to work as a worksheet UDF function.
Function checkArray(rng As Range, Optional a As Variant) As Long
Dim v As Long, vSTRs As Variant
If IsMissing(a) Then
vSTRs = Array("string1", "string2", "string3")
Else
vSTRs = a
End If
For v = LBound(vSTRs) To UBound(vSTRs)
checkArray = checkArray + Application.CountIf(rng, vSTRs(v))
Next v
End Function
The optional a variant array parameter can be passed in as a constant array or it is defined within the function by the default values stored within the function.
Syntax: =checkArray(<range of cells to check>, <optional array of strings>)
Examples: =checkArray(A1:A10)
                  =checkArray(A1:A10, {"abc", "def", "JKL"})
      
This function can also be called from within a Sub to assign a long integer value to a declared variable.
Sub test()
Dim num As Long
num = checkArray(ActiveSheet.Range("A1:A10"), Array("string1", "string2", "string3"))
Debug.Print num
End Sub

Related

How to find the length of an array vba

Sub Test4()
Public Function GetLength(a As Variant) As Integer
If IsEmpty(a) Then
GetLength = 0
Else
GetLength = UBound(a) - LBound(a) + 1
End If
End Function
Essentially trying to find the length of two arrays, and am a little confused on how to use this code to do so. Unsure of what to place where and how to make it work without errors. Any help would be appreciated!
Are you confused because you need to seperate the function from your sub? You should call that function something like:
Sub Test4()
Dim arr As Variant
arr = Array(1, 2, 3)
If IsArray(arr) Then Debug.Print GetLength(arr)
End Sub
Public Function GetLength(a As Variant) As Long
GetLength = UBound(a) - LBound(a) + 1
End Function
I left out IsEmpty if you are to always initialize arr, but put it back if you want to. Just in general, if you are confused on how to call functions and return their values. Have a look at the MS Docs.
The Parameter a represents your Array. The function will return the length of the first dimension of the array it receives as an Argument:
Sub TestIt()
Dim MyArray As Variant
MyArray = Split("A,B,C,D,E,F", ",") 'create an Array of Length 6
MsgBox GetLength(MyArray) 'Output the length of the array, "6"
End Sub
As noted, this may give unexpected results for a 2D array:
[[A][B][C]
[D][E][F]]
This is a 2-by-3 array, so GetLength will tell you that the length is 2. However, the number of elements in the array is 6
(Note - if this is being used in VBA, then there is no advantage to using Integer instead of Long, and I would recommend you change that line - especially since UBound and LBound both return Longs. With too large an array, you could get an Overflow error!)

Is there a way to create a VBA function that can take in both arrays and ranges as input?

I am trying to create a function that can take in both a range or an array to perform some further calculations. When an array passes, the function worked fine, but when the function is used on range in the worksheet, it gives me the VALUE! error.
My code looks like:
Function COMRET(data as variant, N as integer)
Dim nrows as long
If IsArray(data) Then
N = UBound(data,1)
Else
N = data.rows.count
End If
'... some other calculations here
End Function
The problem seems to come from the identification of an array above... other parts of the code seems OK when I comment out the IF section above. Not sure what I am doing wrong here. Appreciate the help. Thanks!
You are correct to declare data as Variant.
When you pass a range into that, it will be correctly passed as Variant/Object/Range, but then things will get a little bit more complicated.
When you call IsArray, which is a mere function, it will try to use the default property of the passed Range object, which is Value. IsArray(Range.Value) is True provided that the Range consist of more than one cell. But when you then call UBound, which is a very special function because it is highlighted as a keyword, it will not try to fetch data.Value and will operate on data directly, and data is a single Range object, so it cannot have an upper bound (while its .Value can).
You need to properly detect what you are being passed:
Public Function COMRET(data As Variant, N As Integer)
Dim nrows As Long
If TypeOf data Is Range Then
N = data.Rows.Count
ElseIf IsArray(data) Then
N = UBound(data, 1)
Else
' ???
End If
End Function
You're passing data as a Variant, which will cause IsArray(data) to always come out as true, regardless of whether you pass a range or array to it when calling the function.
Adding a third compulsory argument would work too, indicating the data type of the data variable:
Function COMRET(data As Variant, Is_Array As Boolean, N As Integer)
Dim nrows As Long
If Is_Array = True Then
N = UBound(data, 1)
Else
N = data.Rows.Count
End If
'... some other calculations here
End Function
Alternatively, you could add a check that uses the error thrown by attempting to use UBound on a range. This clears the need of a third argument:
Function COMRET(data As Variant, N As Integer)
Dim nrows As Long
On Error Resume Next
N = UBound(data, 1)
If Err.Number <> 0 Then N = data.Rows.Count
Err.Clear
On Error GoTo 0
'... some other calculations here
End Function
VarType() should be your friend:
' Const vbArray = 8192 (&H2000)
' Const vbString = 8
Debug.Print VarType(data) ' = vbArray (8192) Or vbString (8) = 8200
' Is data an array of sorts?
Debug.Print CBool((VarType(data) And vbArray) = vbArray)
From MSDN help:
The VarType function never returns the value for vbArray by itself. It
is always added to some other value to indicate an array of a
particular type. The constant vbVariant is only returned in
conjunction with vbArray to indicate that the argument to the VarType
function is an array of type Variant. For example, the value returned
for an array of integers is calculated as vbInteger + vbArray, or
8194. If an object has a default property, VarType (object) returns the type of the object's default property.

What is causing array type mismatch?

I am using a for loop to create an array containing valid order numbers that will then be used as search criteria for another query table. The next for loop searches for each order number in the previously created array and deletes the row if it is not in the array. I'd like to know why I'm getting a type mismatch error in the conditional statement line of the search function. I tried declaring the array as both a variant and as an array with individual string elements. Here is the trimmed down code, thanks in advanced!
Sub VistaArray()
Dim n As Integer, lastrow As Integer, ordern As String, vista() As Variant
'ADDING NEW ELEMENTS TO ORDER NUMBER ARRAY
For n = 2 To lastrow
i = n - 2
ReDim Preserve vista(i)
ordern = Worksheets(Sheet1).Cells(n, 1).Value
vista(i) = ordern
Next n
'REMOVING LINES FROM SECOND TABLE THAT AREN'T IN THE ARRAY
lastrow = Worksheets(Sheet2).Range("A1").End(xlDown).Row
For n = 2 To lastrow
ordn = ActiveSheet.Cells(n, 1).Value
If IsInArray(ordn, vista) Then
Else
'...REMOVE LINE FROM QUERY TABLE...
End If
Next n
End Sub
Function IsInArray(ordn As String, vista As Variant) As Boolean
IsInArray = (UBound(Filter(ordn, vista)) > -1) '***ERROR OCCURS ON THIS LINE***
End Function
The function Filter expects an array for its first argument and a string for its second. You have that reversed. The following should work:
Function IsInArray(ordn As String, vista() As Variant) As Boolean
IsInArray = (UBound(Filter(vista, ordn)) > -1)
End Function

Excel UDF that accepts both Range and Array as Parameter like 'SUM'

I an writing a UDF that needs to accept both Arrays and Ranges.
Usually declaring parameter as variant would work but a Range is an object so this no longer applies. That being said bellow I pasted code that only works when passing an array.
Here is theorethical example, based on SUM:
Function TSUM(numbers() As Variant) As Variant
Dim i As Integer
For i = 1 To UBound(numbers, 1)
TSUM = TSUM + numbers(i)
Next i
End Function
=TSUM({1,1}) Returns 2
=TSUM(A1:B1) Returns #VALUE!
So how can I fix above example to accept Ranges as well?
If you are content to sum the array/range item by item, I would just change to using a For Each loop that works well for either Ranges or Arrays.
Here is that version
Public Function TSUM(numbers As Variant) As Variant
Dim i As Variant
For Each i In numbers
TSUM = TSUM + i
Next i
End Function
If you generally want to work a function based on the type of the argument, you can use TypeName() and switching logic. Here is you function with that approach. I called it TSUM2 for uniqueness.
Public Function TSUM2(numbers As Variant) As Variant
Dim i As Integer
If TypeName(numbers) = "Range" Then
TSUM2 = Application.WorksheetFunction.Sum(numbers)
Else
For i = 1 To UBound(numbers, 1)
TSUM2 = TSUM2 + numbers(i)
Next i
End If
End Function
Note in both examples, I removed the parentheses from the numbers parameters (was numbers() as Variant before). This allows it to accept Range inputs.
If you take the second approach, be sure to debug and verify the TypeNames that could come through.

Assigning an array value to a variable in VBA causes my UDF to exit

I can't seem to figure out why this UDF is exiting on the currentInput = inputArray(i). Here is the relevant code:
Function OrderRange(inputRange As Range) As Variant
Dim length As Integer
inputHeight = inputRange.Count
Dim inputArray As Variant
inputArray = inputRange
Dim strippedArray() As Variant
ReDim strippedArray(0 To (inputHeight - 1))
Dim currentInput As String
Dim i As Integer
For i = 0 To (inputHeight - 1)
currentInput = inputArray(i)
'...computations on currentInput...'
strippedArray(i) = currentInput
Next i
OrderRange = strippedArray
End Function
The debugger reaches currentInput = inputArray(i) but once I move to the next line, the function terminates and a #VALUE! error is entered into the cell I call the function from. I know this is a specific question, but I'm sure it's a general issue and I'll edit this original post to reflect what the general problem is.
Edit: This is an issue regarding assignment of a range to a variant array.
Variant arrays created by setting them equal to ranges have two dimensions even if they are only one column, or row, wide. So if you call the function with A1:A10 you'll get a 10 * 1 array. Also the lower bound of the dimensions will be one, not zero. So you'd have to do something like:
For i = 1 To (inputHeight)
currentInput = inputArray(i, 1)
Also you should use Option Explicit so that you're reminded to declare all variables. InputHeight is never declared.

Resources