VBA Arrays
An array is a data structure which stores a set of sequentially indexed variables of the same data type in a contiguous block of memory. Arrays are used to store lists and tables of data. Arrays can have one dimension or multiple. Arrays in VBA can have a maximum of 60 dimensions. Arrays begin at index 0 by default.
Array Functions
VBA provides a number of useful built-in functions for working with arrays. Note that many high-level functions such as sorting, searching, and getting the length of an array do not exist in VBA. These functions must be implemented by the user. Download and import the modArray module to use high-level functions.
Function | Description |
---|---|
Array | Returns an array of type Variant. Cannot be assigned to a static array. Must be assigned to a dynamic array or a Variant. |
Lbound | Returns the lower bound of an array. Causes an error if the array is not dimensioned. |
Ubound | Returns the upper bound of an array. Causes an error if the array is not dimensioned. |
Join | Returns a string representing all array elements joined by a delimiter. The default delimiter is a space character (Chr 32). |
Split | Splits up a string by a delimiter and places the elements into a string array. The default delimiter is a space character (Chr 32). |
Filter | Returns an array which is a filtered subset of the source array's elements. |
Erase | Resets the elements of a static array to the default value determined by the array's data type. Resets dynamic arrays to an uninitialized state with no values or dimensions. |
ReDim | Reinitializes an array with a new given size. Resets elements to their default values based on the array's type. |
ReDim Preserve | Creates a copy of an array with a new given size. The array's original values are copied into the new array. |
Option Base {0|1}
The Option Base statement sets the default starting index for arrays within a given module. If Option Base is not specified then arrays begin at index 0 by default. Only 0 or 1 can be used with Option Base. Add Option Base followed by 0 or 1 at the top of a module.
Option Base 1
Public Sub Example()
Dim Arr() As Variant
Arr = Array(2, 3, 5)
Debug.Print LBound(Arr) 'Prints 1
Debug.Print UBound(Arr) 'Prints 3
End Sub
Static Vs Dynamic Arrays
Arrays can be declared as static arrays or dynamic arrays.
Static Arrays
Static arrays have a predefined size and number of dimensions. Static arrays are given an explicit lower and upper bound at design-time.
Public Sub Example()
'Explicit lower and upper bound
Dim Arr(0 To 2) As Long
End Sub
The lower bound can be omitted from the declaration. If no lower bound is explicitly given, it is determined by the Option Base statement or it will be 0 by default. Keep in mind that when the lower bound is ommitted, the number provided in the array declaration is the upper bound and not the size of the array.
Public Sub Example()
'Lower bound is implicitly 0 and upper bound is 2
Dim Arr(2) As Long
End Sub
All elements in a static array will be initialized with the default value of the array's type.
Public Sub Example()
Dim Arr(0 To 2) As Long
'Default value for Long is 0
Debug.Print Arr(0) 'Prints 0
Debug.Print Arr(1) 'Prints 0
Debug.Print Arr(2) 'Prints 0
End Sub
Using the Erase statement on a static array resets all values in the array to the default value based on the array's data type and the array keeps its dimensions and size.
Public Sub Example()
Dim Arr(0 To 2) As Long
Arr(0) = 1
Arr(1) = 2
Arr(2) = 3
Debug.Print Arr(0) 'Prints 1
Erase Arr
Debug.Print Arr(0) 'Prints 0 (default value for Long)
End Sub
Dynamic Arrays
Dynamic arrays have no predefined size or dimensions. Dynamic Arrays are dimensioned using the Redim statement or they are dimensioned implicitly when they are assigned an array.
Public Sub Example()
Dim Arr() As Long
ReDim Arr(0 To 2) As Long
Arr(0) = 1
Arr(1) = 2
Arr(2) = 3
End Sub
Public Sub Example()
Dim Arr() As Variant
Arr = Array(1, 2, 3)
End Sub
Using the Erase statement on a dynamic array resets the array to an uninitialized state with no dimensions or size.
Public Sub Example()
Dim Arr() As Variant
Arr = Array(1, 2, 3)
Debug.Print Arr(0) 'Prints 1
Erase Arr
Debug.Print Arr(0) 'Causes Error
End Sub
Variant Arrays
Arrays of any type can be stored in a variable of type Variant. Variant arrays can be assigned using the Array function or by assigning an existing array to a Variant. Assigning an existing array to a Variant creates a copy of the original array and stores it in the Variant.
Public Sub Example()
Dim Arr As Variant
'Assign using Array function
Arr = Array(1, 2, 3, 4, 5)
'Assign copy of another array
Dim LArr(0 To 2) As Long
Arr = LArr
End Sub
Variant Arrays Are Dynamic Arrays
An array stored in a Variant is a dynamic array, even if it was assigned from a static array. Using ReDim and Erase have the same effects on a Variant array that they have on normal dynamic arrays.
Public Sub Example()
Dim LArr(0 To 2) As Long
LArr(0) = 1
LArr(1) = 2
LArr(2) = 3
Dim Arr As Variant
Arr = LArr
Erase Arr
ReDim Arr(0 To 2)
Arr(0) = 1
Arr(1) = 2
Arr(3) = 3
End Sub
Variant Arrays Can Change Type
The data type of a Variant array can be changed using ReDim, which is not permitted for other types of arrays.
Public Sub Example()
Dim LArr() As Long
ReDim LArr(0 To 2)
LArr(0) = 1
LArr(1) = 2
LArr(2) = 3
'ReDim LArr(0 To 2) As Double 'Not Allowed - Causes compile error
Dim Arr As Variant
'Arr is of type Variant/Long()
Arr = LArr
'Arr is now of type Variant/Double()
ReDim Arr(0 To 2) As Double
End Sub
Variant Array Vs Array of Variants
An array stored in a Variant is not the same as an array of type Variant. Arrays stored in Variants can have explicit data types. An array of type Variant is an array of Variants that can store any type of data.
Public Sub Example()
'Variant Array
Dim Arr As Variant
Dim LArr(0 To 2) As Long
LArr(0) = 1
LArr(1) = 2
LArr(2) = 3
'Variant array stores an array with an explicit type
'Arr is of type: Variant/Long()
Arr = LArr
Arr(0) = "Hello" 'Causes error
End Sub
Public Sub Example()
'Array of Variants
Dim VArr(0 To 2) As Variant
'An arrays of Variants can store any type of data
'Array is of type: Variant()
Arr(0) = 1
Arr(1) = True
Arr(2) = "Hello"
End Sub
Bug: Variant Object Array
There is a bug that occurs when using arrays of objects with a Variant. The LBound and UBound functions normally cause a runtime error when used on uninitialized arrays. When LBound or UBound is called on an uninitialized array of objects stored in a Variant, the functions return 0 and -1 respectively. Storing the object array in the Variant also changes the behavior of LBound and UBound on the original object array to also return 0 and -1. Having an array with an upper bound lower than its lower bound is not valid and declaring an array like this explicitly causes a compile error.
Public Sub Example()
Dim Arr
Dim OArr() As Object
'Dim OArr1(0 To -1) As Object 'Compile error
Debug.Print LBound(OArr) 'Causes Error
Debug.Print UBound(OArr) 'Causes Error
Arr = OArr
Debug.Print LBound(Arr) 'Prints 0
Debug.Print UBound(Arr) 'Prints -1
Debug.Print LBound(OArr) 'Prints 0, Does not cause error
Debug.Print UBound(OArr) 'Prints -1, Does not cause error
End Sub
This bug only appears to affect arrays of objects and does not seem to occur for other types.
Public Sub Example()
Dim Arr
Dim LArr() As Long
Arr = LArr
Debug.Print LBound(Arr) 'Causes Error
Debug.Print UBound(Arr) 'Causes Error
End Sub
The implication of this bug is significant in some cases. Consider a function to retrieve the number of dimensions of an array. The condition on line 9 is necessary for the function to work for arrays of objects.
Public Function DimensionsOfArray&(Arr)
If Not IsArray(Arr) Then
Err.Raise 5
End If
Dim i&
i = 1
On Error GoTo Fail
Do Until UBound(Arr, i) < LBound(Arr, i)
DimensionsOfArray = i
i = i + 1
Loop
Fail:
On Error GoTo 0
End Function
Multi-Dimensional Arrays
Multi-Dimensional arrays are arrays that have more than one dimension. Arrays can have a up to 60 dimensions in VBA. Multi-Dimensional arrays are declared using a comma to separate the bounds of each dimension. To access a multi-dimensional array at a specific location, specify the index within each dimension separated by a comma. To get the lower and upper bounds of a specific dimension include the optional dimension argument in the LBound and UBound functions.
Public Sub Example()
Dim Arr(0 To 2, 0 To 2) As Long
Dim i As Long
Dim j As Long
Dim k As Long
For i = LBound(Arr, 1) To UBound(Arr, 1)
For j = LBound(Arr, 2) To UBound(Arr, 2)
Arr(i, j) = k
k = k + 1
Next j
Next i
Debug.Print Arr(0, 0), Arr(0, 1), Arr(0, 2)
Debug.Print Arr(1, 0), Arr(1, 1), Arr(1, 2)
Debug.Print Arr(2, 0), Arr(2, 1), Arr(2, 2)
'0 1 2
'3 4 5
'6 7 8
End Sub
Jagged Arrays
A jagged array is an array of arrays. Jagged arrays are similar to multi-dimensional arrays except instead of multiple dimensions there are multiple levels of nested single-dimensional arrays. A jagged array must be an array of type Variant. To access elements in a jagged array, use a set of parentheses for each level.
Public Sub Example()
Dim Arr(0 To 2) As Variant
Arr(0) = Array(0, 1, 2)
Arr(1) = Array(3, 4, 5)
Arr(2) = Array(6, 7, 8)
Debug.Print Arr(0)(0), Arr(0)(1), Arr(0)(2)
Debug.Print Arr(1)(0), Arr(1)(1), Arr(1)(2)
Debug.Print Arr(2)(0), Arr(2)(1), Arr(2)(2)
'0 1 2
'3 4 5
'6 7 8
End Sub
User-Defined Type Arrays
Arrays can be used with User-Defined Types. An array of a user-defined type can be used instead of a 2D array for storing records of data. Arrays of user-defined types are useful for storing tabular data in a type-safe, meaningful, and memory efficient way. Note that arrays of user-defined types cannot be iterated over using a For Each loop. Arrays of user-defined types are discussed again in the section on user-defined types.
Option Explicit
Public Type ExampleType
Message As String
Number As Long
End Type
Public Sub Example()
Dim Arr(0 To 2) As ExampleType
With Arr(0)
.Message = "Hello"
.Number = 1
End With
With Arr(1)
.Message = "Hi"
.Number = 2
End With
With Arr(2)
.Message = "Hey"
.Number = 3
End With
Debug.Print Arr(0).Message, Arr(0).Number
Debug.Print Arr(1).Message, Arr(1).Number
Debug.Print Arr(2).Message, Arr(2).Number
'Causes Compile Error - For Each cannot be used with array of User-Defined Types
'Dim mt As Variant
'For Each mt In Arr
' Debug.Print mt
'Next mt
End Sub
Assigning Arrays
Arrays can be assigned in a variety of ways.
Directly Assign Elements
Dimensioned arrays can have elements assigned directly by index.
Public Sub Example()
Dim Arr(0 To 2) As Long
'Assign elements individually
Arr(0) = 1
Arr(1) = 2
Arr(2) = 3
'Assign elements directly using a loop
Dim i As Long
For i = Lbound(Arr) To Ubound(Arr)
Arr(i) = i
Next i
End Sub
Array Function
The Array function creates an array of type Variant containing the elements passed as arguments.
Public Sub Example()
Dim Arr() As Variant
Arr = Array(1, 2, 3, 4, 5)
End Sub
Public Sub Example()
Dim Arr As Variant
Arr = Array(1, 2, 3, 4, 5)
End Sub
Split Function
The Split function splits up a string by a delimiter into a string array.
Public Sub Example()
Dim Arr() As String
Arr = Split("1,2,3,4,5", ",")
End Sub
Public Sub Example()
Dim Arr As Variant
Arr = Split("1,2,3,4,5", ",")
End Sub
Excel Ranges
Excel Ranges can be assigned directly to arrays. Assigning a Range to an array will assign a two-dimensional array containing the values in the Range's cells. Even if the Range is only one row or column the array will still be two-dimensional. If the Range contains date or currency type data the Value property of the Range object should be used. Otherwise Value2 can be used.
Public Sub Example()
Dim Arr() As Variant
Arr = Range("A1:C3").Value 'Use if data contains date or currency
Arr = Range("A1:C3").Value2
End Sub
Single cell ranges cannot be assigned to arrays because the Value property of a single cell returns the value of that cell and not an array. When assigning to an array, a type error will occur. When assigning to a Variant, the value will be assigned which would cause an error when attempting to access the Variant as an array.
Public Sub Example()
Dim Arr1() As Variant
Arr1 = Range("A1:C3").Value 'Assigns an array
Arr1 = Range("A1").Value 'Causes error
Dim Arr2 As Variant
Arr2 = Range("A1:C3").Value 'Assigns an array
Arr2 = Range("A1").Value 'Assigns the value in cell A1
Debug.Print Arr2(0) 'Causes error
End Sub
To assign an array to a Range, ensure that the Range is sized correctly to fit the array and that the array is oriented properly. The Resize function can be used to obtain an appropriately sized Range.
Public Sub Example()
Dim Arr(0 To 2, 0 To 2) As Variant
Arr(0, 0) = 1
Arr(0, 1) = 2
Arr(0, 2) = 3
Arr(1, 0) = 4
Arr(1, 1) = 5
Arr(1, 2) = 6
Arr(2, 0) = 7
Arr(2, 1) = 8
Arr(2, 2) = 9
Dim RowCount As Long
RowCount = UBound(Arr, 1) - LBound(Arr, 1) + 1
Dim ColCount As Long
ColCount = = UBound(Arr, 2) - LBound(Arr, 2) + 1
Range("A1").Resize(RowCount, ColCount).Value = Arr
End Sub
To assign a one-dimensional array to a Range, the array may need to be transposed. One-dimensional arrays are equivelent to a row of data. A one-dimensional array can be assigned directly to a row. To assign a one-dimensional array to a column, the array will need to be transposed.
Public Sub Example4()
Dim Arr() As Variant
Arr = Array(1, 2, 3, 4, 5)
'Array can be directly assigned to a row
Range("A1:E1") = Arr
'Array must be transposed to assign to column
Range("A1:A5") = WorksheetFunction.Transpose(Arr)
End Sub
Excel Evaluate Function
The Evaluate function in Excel VBA can be used to assign to an array. Using square brackets around an expression is the same as using the Evaluate function.
Public Sub Example()
Dim Arr() As Variant
Arr = Evaluate("{1, 2, 3}")
Arr = [{1,2,3}]
Arr = Evaluate("{1,2;1,2;1,2}")
Arr = [{1,2;1,2;1,2}]
Arr = Evaluate("=TRANSPOSE({1;2;3;4;5})")
Arr = [=TRANSPOSE({1;2;3;4;5})]
End Sub
Looping Over Arrays
To iterate over an array, use a For loop with the LBound and UBound functions.
Public Sub Example()
Dim Arr() As Long
Redim Arr(0 To 99) As Long
Dim i As Long
For i = LBound(Arr) To UBound(Arr)
Arr(i) = i
Next i
End Sub
To iterate over a multi-dimensional array, include the dimension in the LBound and UBound functions.
Public Sub Example()
Dim Arr() As Long
Redim Arr(0 To 99, 0 To 2) As Long
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)
Arr(i, j) = i
Next j
Next i
End Sub
To iterate over a jagged array, treat each array as a single dimensional array with the LBound and UBound functions.
Public Sub Example()
Dim Arr() As Variant
Redim Arr(0 To 2) As Variant
Arr(0) = Array(1, 2, 3)
Arr(1) = Array(4, 5, 6)
Arr(2) = Array(7, 8, 9)
Dim i As Long
Dim j As Long
For i = LBound(Arr) To UBound(Arr)
For j = LBound(Arr(i)) To UBound(Arr(i))
Debug.Print Arr(i)(j)
Next j
Next i
End Sub
Resizing Arrays
To resize an array, use the Redim Preserve statement. Redim Preserve creates a copy of an array with new dimensions and copies the values from the original array to the new array. ReDim Preserve can be used to increase an array's size to allow for the addition of new elements to the array. Excessive array copying is inefficient so it is best to use an ArrayList data structure to minimize copying.
Note: Be sure to include the Preserve keyword otherwise the values in the array will be erased.
Public Sub Example()
'Add element to array
Dim Arr() As Long
ReDim Arr(0 To 2) As Long
Arr(0) = 1
Arr(1) = 2
Arr(2) = 3
ReDim Preserve Arr(0 To 3) As Long
Arr(3) = 4
End Sub