Excel VBA Pass Cell Array into Function - arrays

I'm trying to write a simple VBA Function like this:
Public Function ReturnMMult(Arr1() As Variant, Arr2() As Variant) As Variant
ReturnMMult = WorksheetFunction.MMult(Arr1,Arr2)
End Function
But it always gives me #VALUE! I've tried changing the Arr's to Ranges, but that doesn't work either. I basically want to be able to write functions that can take ranges like $A1:$A10 or something like that. Looked in a lot of places, and can't figure it out. What am I doing wrong?

something like
Public Function M(a As Excel.Range, b As Excel.Range) As Variant()
Dim a1() As Variant
Dim a2() As Variant
a1 = a.value
a2 = b.value
M = Application.WorksheetFunction.MMult(a1, a2)
End Function

You need to bring them in as ranges then shift them to arrays:
Public Function ReturnMMult(Arr1rng As Range, Arr2rng As Range) As Variant
Dim Arr1() As Variant: Arr1 = Arr1rng.Value
Dim Arr2() As Variant: Arr2 = Arr2rng.Value
ReturnMMult = WorksheetFunction.MMult(Arr1, Arr2)
End Function

This is an example of usage of MMult worksheet function. Please adopt it to your situation.
Sub test()
Dim xArray As Variant, yArray As Variant, zArray As Variant
Dim Fn As Object
Set Fn = Application.WorksheetFunction
xArray = Range("A1:B2").Value
yArray = Range("D1:E2").Value
zArray = Fn.MMult(xArray, yArray)
ActiveCell.Resize(2, 2).Value = zArray
End Sub
MMult returns the #VALUE! error when:
Any cells are empty or contain text.
The number of columns in array1 is different from the number of rows in array2.
The size of the resulting array is equal to or greater than a total of 5,461 cells. Reference WorksheetFunction.MMult method

Related

Using arrays in a loop

Each page (01,02...11,12) represents a month of the year.
Each page has different staff and salaries. I want to see the workers data on these pages in one page. While doing this, I need to do some operations. Since it would be slow in terms of speed, I wanted to do the operations inside the arrays instead of copying this data to a page and performing the operations there.
What I actually want to do and learn.
We can navigate pages one by one in a loop. I want to do the same for arrays (1st array, 2nd array, ... 11 array, 12 array).
Option Explicit
Option Base 1
Dim d1() As Variant, d2() As Variant, d3() As Variant, d4() As Variant, d5() As Variant, d6() As Variant
Dim d7() As Variant, d8() As Variant, d9() As Variant, d10() As Variant, d11() As Variant, d12() As Variant
Dim personel As Collection, sonuc() As Variant, d() As Variant
Sub Example()
Dim i As Integer
For i = 1 To Worksheets.Count
Debug.Print Worksheets(i).Name
Next i
End Sub
Sub Example2()
Dim i As Integer
For i = 1 To 12
' ???? d & i = Worksheets(i).Range("A1:AA34")
Next i
End Sub
I recommend creating a 2 dimensional array of data where each elemnt holds the information for a single worksheet.
Creating an Employee class would make the life easier in the long run. WatchClass Modules Explained in Simple English (with examples)
Sub Main()
Dim Data As Variant
Data = AllWorkSheetData
Stop
End Sub
Function AllWorkSheetData() As Variant()
Dim Result As Variant
ReDim Result(1 To Worksheets.Count)
Dim i As Long
For i = 1 To Worksheets.Count
Result(i) = Worksheets(i).Range("A1:AA34")
Next i
AllWorkSheetData = Result
End Function
Do you need 12 different arrays for your operation?
If you want to paste the data one after the other on a single sheet, you can use a single array and reassign values in each iteration.
Dim d() As Variant, i As Integer
For i = 1 to Worksheets.Count
d = Worksheets(i).Range("A1:AA34").Value2
'Do your calculations with d array.
'
'
'
'Paste d array in aggregate sheet.
Next i
Also, use Excel object datatypes along with For Each loop instead of integers. It is much better to understand.
Dim ws As Worksheet
Dim d() As Variant
For Each ws In Worksheets
d = ws.Range("A1:AA34").Value2
'Do your calculations with d array.
'
'
'
'Paste d array in aggregate sheet.
Next ws
You need to create an array to hold variants that you are connecting on to the data from your sheet:
Dim d(1 To 12) As Variant
Dim i As Integer
For i = 1 To 12
d(i) = Worksheets(i).Range("A1:AA34")
Debug.Print d(i)(1, 1) ' access one the value from one cell of the sheet that has been read into the array.
Next i
End Sub

Element wise array operations in VBA Function

I have created a custom Function in VBA, the inputs to which are a cell value and three different ranges of the same length. The code is as below more or less:
Public Function MYTEST(CELLVALUE As Double, ByRef INPRNG As Range, ByRef RNG1 As Range, ByRef RNG2 As Range)
Dim i As Double
DIM A As Double
DIM B As Double
Dim MODRNG As Range
For i = LBound(INPRNG) To UBound(INPRNG)
MODRNG(i) = INPRNG(i) * RNG1(i) + CELLVALUE * RNG2(i)
Next i
A= MODRNG.Cells(1,1)
B= MODRNG.Cells(2,1)
mytest =A+B
End Function
I get a #VALUE! error when I run this code.
My question is three fold:
Are my variables/ranges declared incorrectly or is the For loop causing issues?
Is there a way to use For Each loop instead of For Next?
Can I do the array operation (of the for loop) in my excel worksheet and send the modified array to the function?
Please see the snap shot for clarity.
Thanks!
I'm not sure if I understood your goal, but this will throw a number taking from first and second (cell/array position) for the MODRNG.
Option Explicit
Public Function MYTEST(CELLVALUE As Double, ByRef INPRNG As Range, ByRef RNG1 As Range, ByRef RNG2 As Range) As Long
Dim i As Double
Dim A As Double
Dim B As Double
ReDim MODRNG(1 To INPRNG.Cells.Count)
For i = 1 To INPRNG.Cells.Count
MODRNG(i) = INPRNG(i) * RNG1(i) + CELLVALUE * RNG2(i)
Next i
A = MODRNG(1)
B = MODRNG(2)
MYTEST = A + B
End Function
thought If you only want the first and second values, I don't see why would you take a range bigger than 2 cells.

Assigning an array to another array in one line

I'm new to VBA, and I can't seem to work out a very simple concept - assigning one array to another, both being of equal size and type. Like in this example:
Option Explicit
Sub main()
Dim arr1(2), arr2(2) As Double
arr1(0) = 5
arr1(1) = 10
arr2 = arr1 'error here
Debug.Print arr2(0)
Debug.Print arr2(0)
End Sub
Running this returns an error
"Can't assign to array"
Now, I know I can iterate through every element with a For loop, but in some advanced cases, it is impractical to use - for example, I have a slow-loading function that returns an array, and because of that, I'd like to run it only once, taking it's whole return value and assigning to some other array, like this:
arr1 = Very_Slow_Function_That_Returns_An_Array()
But obviously, this won't work either, and will produce the same error. So, what can be done? Can someone give some advice on how to assign a whole array to another array without having to iterate through every element?
You can assign an array to another in VBA like this:
Option Explicit
Sub main()
Dim arr1 As Variant
Dim arr2 As Variant
arr1 = Array(5, 10)
'Assign array1 to array2
arr2 = arr1
Debug.Print arr1(0)
Debug.Print arr2(0)
End Sub
These variations work:
Sub main()
Dim arr1() As Double, arr2() As Double
ReDim arr1(0 To 1)
arr1(0) = 5
arr1(1) = 10
arr2 = arr1
End Sub
or
Sub main()
Dim arr1() As Variant, arr2() As Variant
arr1 = Array(5, 10)
arr2 = arr1
End Sub
Third variation which is closest to OP code:
Sub main()
Dim arr1(0 To 1) As Double, arr2() As Double
arr1(0) = 5
arr1(1) = 10
arr2 = arr1 'no error here now.
End Sub

UBound function doesn't work when passing a Named Range as Variant

MyArray is a (100 row x 1 column) named range containing integers.
This doesn't work:
Function myFunc(MyArray As Variant)
myFunc = UBound(MyArray)
Nor does this:
Function myFunc(MyArray As Variant)
myFunc = UBound(MyArray, 1)
I'm sure this is a rather basic error, but I've done a fair amount of Googling and failed to work out the answer for myself. Help would be much appreciated.
Make sure you're passing a variant array, not a Range object. The function accepts a variant data type, which can be anything. In order to ensure it's an array, pass the .Value
Sub Test()
Debug.Print myFunc(Range("A1:A50").Value)
End Sub
Function myFunc(MyArray As Variant)
myFunc = UBound(MyArray, 1)
End Function

Moving an Array to a Range VARIABLE

I am trying to find this but I can't! Is it possible to move/copy and VBA Array to a Range Variable, I am not saying a Range cells, it's a Range that you declare (ex: DIM ran as Range)
I want something like this:
Public Function test()
Dim ran As Range
Dim myArray(4) As Integer
myArray(1) = 1
myArray(2) = 2
myArray(3) = 3
myArray(4) = 4
'If I do this, it works!
Range("A1:A4") = myArray
'But I want this and it does not work!
ran = myArray
End Function
Thanks!
Even though the Range is declared in code, it's still a Range, not an array. If myArray is actually a Range object (in which case you should re-think your naming conventions) you should be able to do what your example showed.
However if your variable myArray is some other type of object (like and array) you can't just set it like that, you would have to write a method that converts myArray to a range.
EDIT:
I'm guessing that the reason that Range("A1:A4") = myArray works is because the assignment operator has been overloaded to support it as short-hand for Range("A1:A4").Value = myArray.
A Range however is not just an array, it's a data structure specific to Ranges of a workbook
When you declare Dim ran As Range you haven't actually initialized your Range object yet. I'm guessing that if you did the following it would work:
Dim ran As Range("A1:A4")
Dim myArray(4) As Integer
myArray(1) = 1
myArray(2) = 2
myArray(3) = 3
myArray(4) = 4
ran = myArray
If you set a variant to a worksheet range you get a 2 dimensional array. Try this
Sub MoveArray()
Dim myArray
myArray = Range("A1:B3").Value
Range("A6:B8").Value = myArray
End Sub
Or this
Sub MoveArray2()
Dim myArray
Dim myArray2
Dim myRange
Dim i As Integer
Dim j As Integer
myArray = Range("A1:B3").Value
Set myRange = Range("A6:B8")
For i = 1 To myRange.Rows.Count
For j = 1 To myRange.Columns.Count
myRange.Cells(i, j) = myArray(i, j)
Next j
Next i
myArray2 = myRange
End Sub
In either case the variant becomes an array rather than a range object and the loops set the values of the range from the array.
Edit
As you can see from the comments in the questions/answers in this thread a range is not an array, it is a complex object that has many properties and methods. One of the properties (I think the default property) is value. This property is in fact a 2 dimensional array (or at least behaves like one) of the values of the cells in the range. As such if myArray is also a 2 dimsensional aray the code myRange = myArray will execute. What will happen is the value of the cells that the range refers to will be set to the values in the array. The range refers to these cells, but it is the values in the cells that change rather than the range object.
As such if if you transfer a range to a diferent set of cells the new set of cells retains it's values.
On a practical side if you want to change the values of the cells that a range referes to you can do it as shown below:
Sub Test1()
Dim myArray(1 To 4, 1 To 1)
Dim myRange As Range
myArray(1, 1) = 1
myArray(2, 1) = 2
myArray(3, 1) = 3
myArray(4, 1) = 4
Set myRange = Range("A1:A4")
myRange = myArray
End Sub

Resources