Excel return array from function

In September, 2018 we announced that Dynamic Array support would be coming to Excel. This allows formulas to spill across multiple cells if the formula returns multi-cell ranges or arrays. This new dynamic array behavior can also affect earlier functions that have the ability to return a multi-cell range or array. 

Below is a list of functions that could return multi-cell ranges or arrays in what we refer to as pre-dynamic array Excel. If these functions were used in workbooks predating dynamic arrays, and returned a multi-cell range or array to the grid (or a function that did not expect them), then silent implicit intersection would have occurred. Dynamic array Excel indicates where implicit intersection could occur using the @ operator, and as a result, these functions may be prepended with an @ if they were originally authored in a pre-dynamic array version of Excel. Additionally, if authored on dynamic array Excel, these functions may appear as legacy array formulas in pre-dynamic array Excel unless prepended with @. 

  • CELL

  • COLUMN

  • FILTERXML

  • FORMULATEXT

  • FREQUENCY

  • GROWTH

  • HYPERLINK

  • INDEX

  • INDIRECT

  • ISFORMULA 

  • LINEST

  • LOGEST

  • MINVERSE

  • MMULT

  • MODE.MULT

  • MUNIT

  • OFFSET

  • ROW

  • TRANSPOSE

  • TREND

  • All User Defined Functions

Need more help?

You can always ask an expert in the Excel Tech Community or get support in the Answers community.

Need more help?

Want more options?

Explore subscription benefits, browse training courses, learn how to secure your device, and more.

Communities help you ask and answer questions, give feedback, and hear from experts with rich knowledge.

All,

I would like to write a function to return an array of integers so I can index them, but I am not aware of the syntax for VBA. Here is the pseudo code:

function getStats() as integer
    dim returnVal(4) as integer
    returnVal(0)=c2percent14
    returnVal(1)=c3percent14
    returnVal(2)=c4percent14
    returnVal(3)=c5percent14
    getStats=returnVal
end function

msgbox getStats(3)

where these values are all integers, or should be, and then I can index the return array for the stat that I want. Thanks.

-Rik

moffeltje's user avatar

moffeltje

4,4644 gold badges32 silver badges56 bronze badges

asked Jul 22, 2015 at 13:39

Rik's user avatar

Give the function the type as an array:

function getStats() as Integer()    
    dim returnVal(0 to 3) as integer

    returnVal(0) = c2percent14
    returnVal(1) = c3percent14
    returnVal(2) = c4percent14
    returnVal(3) = c5percent14

    getStats = returnVal
end function

Sub mysub()
   Dim myArray() As Integer

   myArray = getStats()

   msgbox myArray(3)
end sub 

GSerg's user avatar

GSerg

75.3k17 gold badges160 silver badges340 bronze badges

answered Jul 22, 2015 at 13:50

moffeltje's user avatar

moffeltjemoffeltje

4,4644 gold badges32 silver badges56 bronze badges

2

Function getStats() As Variant
    getstats = Array(c2percent14, c3percent14, c4percent14, c5percent14)
End Function

Sub mysub()
    Dim myArray() As Variant
    myArray = getStats()
    msgbox myArray(3)
End Sub 

getStats is now an Array of type ´Variant´. The drawback of this method is that you effectively have no static typing anymore, since Variant could be anything.

ascripter's user avatar

ascripter

5,47512 gold badges49 silver badges67 bronze badges

answered Jul 22, 2015 at 13:47

Tim's user avatar

TimTim

2,6333 gold badges25 silver badges47 bronze badges

1

I’m going to add an answer here because I’m happy to say, after hours of frustration and bad information, I finally know how to return arrays! Here is how you return an array from a function:

Sub mysub()
    Dim i As Integer, s As String
    Dim myArray() As Integer 'if you declare a size here you will get "Compile error, can't assign to array"
    myArray = getStats()

    s = "Array values returned:" & vbCrLf
    For i = 0 To UBound(myArray)
        s = (s & myArray(i) & " ")
    Next
    MsgBox s
End Sub

Function getStats() As Integer() 'The return type must be EXACTLY the same as the type declared in the calling sub.
    Dim returnVal(2) As Integer 'if you DON'T declare a size here you will get "Run-time error '9': Subscript out of range"

    returnVal(0) = 0
    returnVal(1) = 1
    returnVal(2) = 2
    'returnVal(3) = 3 This will throw an error. Remember that an array declared (2) will hold 3 values, 0-2.
    getStats = returnVal
End Function

Output:
enter image description here

The comments I included here are very important. Although VBA is usually pretty lax, this particular thing is very picky. These are required for your function, assignment, and return to work:

  • The array declared in the calling sub has to be of undeclared length.
  • The function that returns an array has to be of EXACTLY same type. Even if you declare the array in the sub as a Variant and the function returns an Integer array that will not work either.
  • You have to use a temporary array in the function. You cannot assign values to the function name (getStats) like you normally would in a function; you can only assign the temporary array to the function name once you have assigned all the values to the temp array. Any attempt to ReDim getStats as an array will also throw an error.
  • The temp array has to be declared with length. In VBA you cannot assign values to an array at an index until you declare the length.

answered Apr 19, 2020 at 5:25

SendETHToThisAddress's user avatar

5

Return to VBA Code Examples

This article will demonstrate how to return an Array using a VBA Function.

VBA Function Return Array

When using functions to return arrays, I strongly recommend declaring arrays with type variant:

    Function ReturnArray() As Variant

    End Function

Variant Arrays are easier to work with. Array size becomes less of a concern.

Function Return Array Examples

Here is an example of a function that returns an array:

Function ReturnArray() As Variant
    Dim tempArr As Variant
    
    'Create New Temp Array
    ReDim tempArr(1 To 3, 1 To 2)
    
    'Assign Array Values
    tempArr(1, 1) = "Steve"
    tempArr(1, 2) = "Johnson"
    tempArr(2, 1) = "Ryan"
    tempArr(2, 2) = "Johnson"
    tempArr(3, 1) = "Andrew"
    tempArr(3, 2) = "Scott"
    
    'Output Array
    ReturnArray = tempArr
    
End Function
 
Sub TestTransposeArray()
    Dim outputArr As Variant
    
    'Call Return Function
    outputArr = ReturnArray()
    
    'Test Output
    MsgBox outputArr(2, 1)
 
End Sub

Notice we declared the Arrays with data type = variant to avoid size issues.

This example takes an array as an input, transposes the array, and outputs the new transposed array:

Function TransposeArray(MyArray As Variant) As Variant
    Dim x As Long, y As Long
    Dim maxX As Long, minX As Long
    Dim maxY As Long, minY As Long
    
    Dim tempArr As Variant
    
    'Get Upper and Lower Bounds
    maxX = UBound(MyArray, 1)
    minX = LBound(MyArray, 1)
    maxY = UBound(MyArray, 2)
    minY = LBound(MyArray, 2)
    
    'Create New Temp Array
    ReDim tempArr(minX To maxX, minY To maxX)
    
    'Transpose the Array
    For x = minX To maxX
        For y = minY To maxY
            tempArr(y, x) = MyArray(x, y)
        Next y
    Next x
    
    'Output Array
    TransposeArray = tempArr
    
End Function

Sub TestTransposeArray()
    Dim testArr(1 To 3, 1 To 2) As Variant
    Dim outputArr As Variant
    
    'Assign Array Values
    testArr(1, 1) = "Steve"
    testArr(1, 2) = "Johnson"
    testArr(2, 1) = "Ryan"
    testArr(2, 2) = "Johnson"
    testArr(3, 1) = "Andrew"
    testArr(3, 2) = "Scott"
    
    'Call Transpose Function
    outputArr = TransposeArray(testArr)
    
    'Test Output
    MsgBox outputArr(2, 1)

End Sub

VBA Coding Made Easy

Stop searching for VBA code online. Learn more about AutoMacro — A VBA Code Builder that allows beginners to code procedures from scratch with minimal coding knowledge and with many time-saving features for all users!
vba save as

Learn More!

Today I’m going to show you how to return an array from a VBA function. VBA functions can return arrays of any data type. But sometimes we need to return arrays with elements of different data types. Luckily we can do it using the variant data type. I will show how to return an array of type variant in an example. Let’s start with a simple example. Assume we want to create a VBA function which returns 3 random numbers between 1 and 100. The VBA function can return these 3 numbers as an array. We can use the inbuilt function called Rnd to generate a random number. Then we can do some additional calculations and use the VBA Int function to get a number between 1 and 100. Here is how you can do it.

Function ThreeRandomNumbers() As Integer()

     Dim ResultArr(2) As Integer

     ResultArr(0) = Int(Rnd * 100) + 1
     ResultArr(1) = Int(Rnd * 100) + 1
     ResultArr(2) = Int(Rnd * 100) + 1

     ThreeRandomNumbers = ResultArr

End Function

Rnd function return values similar to this.

0.8626193
0.7904852
0.3735362

So I multiplied those numbers by 100.

86.26193
79.04852
37.35362

And the VBA Int function returns the integer part of the number. So finally we get random numbers like below.

86
79
37

Rnd function returns values equal or greater than 0 and less than 1. Then Int(Rnd * 100) will output numbers from 0 to 99. Therefore we have to add 1 to get a random number between 1 and 100.

Int(Rnd * 100) + 1 => Generates integer values between 1 and 100

Now we have a VBA function which can return an array. Let’s see how we can call this function within a subroutine. Data type of the array returned by our function is integer. So we need an array of the type integer inside our subroutine. Then we can assign the function’s return value to that array.

Sub Test1()

     Dim RandomNumbers() As Integer

     RandomNumbers = ThreeRandomNumbers()

End Sub

Add a breakpoint at End Sub and run the subroutine. Then you will see the result in the Locals window like this.

View the array returned by the function in the Locals window

Also you can print these values to an Excel sheet as well. If the name of the worksheet is “Sheet1” then you can write the array to the worksheet as follows.

Sub Test2()

     Dim WS As Worksheet
     Dim RandomNumbers() As Integer
     Dim i As Integer

     Set WS = Worksheets(«Sheet1»)
     RandomNumbers = ThreeRandomNumbers()

     For i = 0 To 2
          WS.Range(«A1»).Offset(i, 0).Value = RandomNumbers(i)
     Next i

End Sub

Here is the result of the Test2 subroutine.

Write the returned array of the function to a worksheet

Next let’s look at another example where we need to pass arguments to the VBA function. Assume we need to find 5 powers/exponents of a given number. For an example if the given number is 3 then the VBA function should return 1,3,9,27 and 81 (30,31,32,33,34)

Here we have to pass the given number as an argument to the function. Then the function can return 5 exponents of the number as an array.

Function FiveExponents(GivenNumber As Integer) As Integer()

     Dim ResultArr(4) As Integer

     ResultArr(0) = GivenNumber ^ 0
     ResultArr(1) = GivenNumber ^ 1
     ResultArr(2) = GivenNumber ^ 2
     ResultArr(3) = GivenNumber ^ 3
     ResultArr(4) = GivenNumber ^ 4

     FiveExponents = ResultArr

End Function

.

Now we can call this function within a subroutine like this.

Sub Test3()

     Dim WS As Worksheet
     Dim Exponents() As Integer
     Dim i As Integer

     Set WS = Worksheets(«Sheet1»)
     Exponents = FiveExponents(5)

     For i = 0 To 4
          WS.Range(«A1»).Offset(i, 0).Value = Exponents(i)
     Next i

End Sub

Below is the outcome of the above subroutine.

VBA function returned five exponents of the given number as an array

Above functions output arrays of integer data type. So the returned array consists of only integers. But sometimes we need VBA functions which should return arrays with elements of various data types. They may contain values of data types such as integer, string, boolean etc. Here is an example.

Sample data sheet

This worksheet contains order information of a shop. Assume we need a VBA function which takes an order id as an argument and then returns all the other information of that order as an array. It is a type of function we need when searching data. So here various columns have various data types. Therefore we need to declare the data type of the return value of the function as the variant.

This is the function developed for the above requirement.

Function GetOrderInformation(OrderId As String) As Variant

     Dim WS As Worksheet
     Dim WS_LastRow As Long
     Dim i As Long
     Dim j As Integer
     Dim ResultArr(6) As Variant

     Set WS = Worksheets(«Order Details»)

     WS_LastRow = WS.Cells.Find(«*», [A1], , , xlByRows, xlPrevious).Row

     For i = 2 To WS_LastRow
          If StrComp(WS.Range(«A» & i).Value, OrderId, vbTextCompare) = 0 Then
               For j = 0 To 6
                    ResultArr(j) = WS.Range(«A» & i).Offset(0, j).Value
               Next j
               Exit For
          End If
     Next i

     GetOrderInformation = ResultArr

End Function

First we find the last row of the worksheet. Then use For Next Statement to iterate through the rows. Strcomp function is used to find the matching row for the given order id. If a matching row is found then all the information of that row is written to an array.

Here is how you can call the above function inside a subroutine.

Sub Test4()

     Dim OrderInfo() As Variant

     OrderInfo = GetOrderInformation(«209-2752429-9545»)

End Sub

Add a breakpoint at End Sub and run the macro. Then you can view the OrderInfo array in the Locals window.

Array of type variant returned by the function

Also read
Quickly Write Multidimensional Array to Excel Range

Re-size Dynamic Arrays
Calculate With Arrays
How to use preserve keyword in arrays
Transposing an Array in VBA

ThreeWave
Returning Arrays From VBA User Defined Functions

This page describes returning arrays as the result of VBA User Defined Functions.
ShortFadeBar

If you often write your own User Defined Functions (UDFs) in VBA or in a COM or Automation Add-Ins (click
here for information about writing your own functions in VBA; click
here for information about writing COM Add-Ins, or click
here for information about writing Automation Add-Ins), you have likely needed to or
at least found it useful to return an array as the result of your VBA function. This allows the user to array enter
your function (click here for information about array formulas) into a range of cells
on the worksheet to display the contents of the array that is returned by your UDF.

This page looks at a few issue that might arise when you are returning arrays from UDFs.

SectionBreak

At its simplest, the size of the returned array can be mandated by the function and require that the user use an array that size
in order to get all the results. The Excel function LINEST function works this way. You must
array-enter that function into a range of cells that is 5 rows tall and 2 columns wide. If you enter it into a larger range,
Excel fills out the unused elements of the range with #N/A errors. If you enter it into a smaller
range, you will not get all the values created by LINEST.

To mandate the size of the returned array, simply declare the array to that size and setting the result of the function to that
array. For example,

    Function Test() As Variant
        Dim V() As Variant
        Dim N As Long
        Dim R As Long
        Dim C As Long
        ReDim V(1 To 3, 1 To 4)
        For R = 1 To 3
            For C = 1 To 4
                N = N + 1
                V(R, C) = N
            Next C
        Next R
        Test = V
    End Function

This function simply returns an array with 3 rows and 4 columns that contains the integers from 1 to 12.

Returning such a fixed-size array can be useful if the number of results does not vary with the number and/or values of the
inputs to the function. However, this is usually not the case.

In the majority of circumstances, if your UDF is going to return an array, that array will vary in size and the size will depend
on any one or more of three things: the size of the range into which the UDF was entered, the number of elements passed into
the function, and, of course, the nature and function of the UDF itself. The Application.Caller object,
when used in a UDF called from a worksheet range, is a Range reference to the range from which your UDF was called.

CAUTION: Application.Caller will be a Range object only when the function in which it appears
was called from a worksheet cell. If the function was called from another VB procedure, Application.Caller
will be an Error-type Variant and most any attempt to use it will result in a Type Mismatch (13) error. If the code containing
Application.Caller was called via the OnAction property of a Shape object on
a worksheet, Application.Caller will be a String containing the name of the sheet. Therefore, if your
function might be called from another VB procedure rather than only from a worksheet cell, you should test
Application.Caller with the IsObject function to ensure that it is indeed
an object before attempting to access any of its properties.

CAUTION: In Excel 2003, a new object, Application.ThisCell, was introduced. It is similar in nature to
Application.Caller, but differs when a UDF is array entered into a range of more than one cell.
Application.Caller will return the a Range reference to the entire range in which the UDF was array-entered.
Application.ThisCell returns a reference to the first (upper left) cell in the range from which the UDF
was called. Frankly, I’m not sure why Application.ThisCell was introduced in the first place.

In the example code on this page, we will not test Application.Caller with IsObject.
For simplicity and brevity, we will assume that the function is being called from a worksheet.

Using Application.Caller, you can determine the number of rows and columns from which the function
was called. For example,

    Function Test()
        Dim CallerRows As Long
        Dim CallerCols As Long
        With Application.Caller
            CallerRows = .Rows.Count
            CallerCols = .Columns.Count
        End With
        Test = CallerRows * CallerCols
    End Function

In this code, the variables CallerRows and CallerCols get the number of rows
and columns in the range from which the function was called. If you want to return an array the same size as the range from
which the function was called, you can use code like the following:

Function Test() As Variant
    Dim CallerRows As Long
    Dim CallerCols As Long
    Dim CallerAddr As String
    Dim Result() As Long
    Dim N As Long
    Dim RowNdx As Long
    Dim ColNdx As Long
        
    With Application.Caller
        CallerRows = .Rows.Count
        CallerCols = .Columns.Count
    End With
    ReDim Result(1 To CallerRows, 1 To CallerCols) 
    For RowNdx = 1 To CallerRows
        For ColNdx = 1 To CallerCols
            N = N + 1
            Result(RowNdx, ColNdx) = N
        Next ColNdx
     Next RowNdx
     Test = Result
End Function

This function returns an array with the same dimensions as the range from which the function was called, and simply fills those
elements with the first Rows*Columns integers.

You can, of course, ignore the size of the range from which the function was called and return an array with the dimensions
required by your function’s purpose. In this case, if the function is entered into a range smaller than the result array of
the function, the result array is trunctated on the bottom and on the right to the size of the calling range. If the function
was entered into a range larger than the size of the returned array, Excel fills the unused cells with #N/A
values. This is the normal behavior of Excel’s own array functions. For example, if you array enter
=ROW(A1:A3) into cells B1:B5, the result will be
1 2 3 #N/A #N/A. The ROW(A1:A3) returns an array with only three elements,
so Excel fills in the rest of the calling range with #N/A values.

SectionBreak

If your UDF creates a 1-dimensional array as its result, it can orient the array as either a row vector or a column vector so that
is will be properly displayed in the worksheet cells without requiring the user to wrap your UDF result in a TRANSPOSE
function. If the function was called from a row vector of cells (e.g., A1:E1), it does not need to
be transposed. If the function was called from a column vector of cells (e.g., A1:A5), the array needs
to be transposed. The code below looks at Application.Caller.Rows.Count and if this is greater than
1, it tranposes the array before returning it to the caller. Note that this should be done only with single-dimensional
arrays and only when the UDF is being called from a worksheet range. Therefore, you should first test
Application.Caller with IsObject and then test
Application.Caller.Rows.Count and Application.Caller.Columns.Count to test
if it is being called from a row or column vector. For example,

    Function Test(NN As Long)
        Dim Result() As Long
        Dim N As Long
        ReDim Result(1 To NN)
        For N = 1 To NN
            Result(N) = N
        Next N
        If Application.Caller.Rows.Count > 1 Then
            Test = Application.Transpose(Result)
        Else
            Test = Result
        End If
    End Function

You can, of course, forego this and return the array as-is and leave it up to the user to use the TRANSPOSE
function to properly orient the array.

This page last updated: 6-Nov-2007

Like this post? Please share to your friends:
  • Excel responding and not responding
  • Excel save csv format
  • Excel resize all columns
  • Excel save all shortcut
  • Excel required rate of return