Excel VBA Array - The Complete Guide - Excel Macro Mastery
Excel VBA Array - The Complete Guide - Excel Macro Mastery
com/excel-vba-array/
Webinars About
This post provides an in-depth look at the VBA array which is a very important part of
the Excel VBA programming language. It covers everything you need to know about the
VBA array.
We will start by seeing what exactly is the VBA Array is and why you need it.
Below you will see a quick reference guide to using the VBA Array. Refer to it anytime
you need a quick reminder of the VBA Array syntax.
The rest of the post provides the most complete guide you will �nd on the VBA array.
Contents [hide]
10.1 Using the For Each Loop with the VBA Array
Next i Or
Or For i = LBound(arr,1) To UBound(arr,1)
For i = Next i
LBound(arr,1) To
UBound(arr,1)
Next i
UBound(arr,1) Next j
For j = Next i
LBound(arr,2) To
UBound(arr,2)
Next j
Next i
If we wish to store the marks of another student then we need to create a second
variable.
Student Marks
We are going to read these marks and write them to the Immediate Window.
Note: The function Debug.Print writes values to the Immediate Window. To view this
window select View->Immediate Window from the menu( Shortcut is Ctrl + G)
As you can see in the following example we are writing the same code �ve times – once
for each student:
' https://excelmacromastery.com/
Public Sub StudentMarks()
End Sub
Output
The problem with using one variable per student is that you need to add code for each
student. Therefore if you had a thousand students in the above example you would
need three thousand lines of code!
Luckily we have arrays to make our life easier. Arrays allow us to store a list of
data items in one structure.
The following code shows the above student example using an array:
' ExcelMacroMastery.com
' https://excelmacromastery.com/excel-vba-array/
' Author: Paul Kelly
' Description: Reads marks to an Array and write
' the array to the Immediate Window(Ctrl + G)
' TO RUN: Click in the sub and press F5
Public Sub StudentMarksArr()
' Print student marks from the array to the Immediate Window
Debug.Print "Students Marks"
For i = LBound(Students) To UBound(Students)
Debug.Print Students(i)
Next i
End Sub
The advantage of this code is that it will work for any number of students. If we have to
change this code to deal with 1000 students we only need to change the (1 To 5) to (1 To
1000) in the declaration. In the prior example we would need to add approximately �ve
thousand lines of code.
Let’s have a quick comparison of variables and arrays. First we compare the declaration:
' Variable
Dim Student As Long
Dim Country As String
' Array
Dim Students(1 To 3) As Long
Dim Countries(1 To 3) As String
The fact that arrays use an index(also called a subscript) to access each item is
important. It means we can easily access all the items in an array using a For Loop.
Now that you have some background on why arrays are useful let’s go through them
step by step.
The di�erence between these types is mostly in how they are created. Accessing values
in both array types is exactly the same. In the following sections we will cover both of
these types.
' https://excelmacromastery.com/
Public Sub DecArrayStatic()
' Create array with locations 2,3,4 ' This is rarely used
Dim arrMarks4(2 To 4) As Long
End Sub
An Array of 0 to 3
As you can see the length is speci�ed when you declare a static array. The problem with
this is that you can never be sure in advance the length you need. Each time you run the
Macro you may have di�erent length requirements.
If you do not use all the array locations then the resources are being wasted. So if you
need more locations you can use ReDim but this is essentially creating a new static
array.
The dynamic array does not have such problems. You do not specify the length when
you declare it. Therefore you can then grow and shrink as required:
' https://excelmacromastery.com/
Public Sub DecArrayDynamic()
' Set the length of the array when you are ready
ReDim arrMarks(0 To 5)
End Sub
The dynamic array is not allocated until you use the ReDim statement. The advantage is
you can wait until you know the number of items before setting the array length. With a
static array you have to state the length upfront.
To give an example. Imagine you were reading worksheets of student marks. With a
dynamic array you can count the students on the worksheet and set an array to that
length. With a static array you must set the length to the largest possible number of
students.
' https://excelmacromastery.com/
Public Sub AssignValue()
End Sub
The number of the location is called the subscript or index. The last line in the example
will give a “Subscript out of Range” error as there is no location 4 in the array example.
' https://excelmacromastery.com/
Function ArrayLength(arr As Variant) As Long
On Error Goto eh
' Loop is used for multidimensional arrays. The Loop will terminate when a
' "Subscript out of Range" error occurs i.e. there are no more dimensions.
Dim i As Long, length As Long
length = 1
Done:
Exit Function
eh:
If Err.Number = 13 Then ' Type Mismatch Error
Err.Raise vbObjectError, "ArrayLength" _
, "The argument passed to the ArrayLength function is not an array."
End If
End Function
' 0 items
Dim arr1() As Long
Debug.Print ArrayLength(arr1)
' 10 items
Dim arr2(0 To 9) As Long
Debug.Print ArrayLength(arr2)
' 18 items
Dim arr3(0 To 5, 1 To 3) As Long
Debug.Print ArrayLength(arr3)
End Sub
The array created by the Array Function will start at index zero unless you use Option
Base 1 at the top of your module. Then it will start at index one. In programming, it is
generally considered poor practice to have your actual data in the code. However,
sometimes it is useful when you need to test some code quickly.
The Split function is used to split a string into an array based on a delimiter. A delimiter
is a character such as a comma or space that separates the items.
The following code will split the string into an array of four elements:
Dim s As String
s = "Red,Yellow,Green,Blue"
The Split function is normally used when you read from a comma-separated �le or
another source that provides a list of items separated by the same character.
The following example assigns random numbers to an array using a loop. It then prints
out these numbers using a second loop.
' https://excelmacromastery.com/
Public Sub ArrayLoops()
End Sub
The functions LBound and UBound are very useful. Using them means our loops will
work correctly with any array length. The real bene�t is that if the length of the array
changes we do not have to change the code for printing the values. A loop will work for
an array of any length as long as you use these functions.
In the following code the value of mark changes but it does not change the value in the
array.
The For Each is loop is �ne to use for reading an array. It is neater to write especially for
a Two-Dimensional array as we will see.
Debug.Print mark
Next mark
For a static Array the Erase function resets all the values to the default. If the array is
made up of long integers(i.e type Long) then all the values are set to zero. If the array is
of strings then all the strings are set to “” and so on.
For a Dynamic Array the Erase function DeAllocates memory. That is, it deletes the
array. If you want to use it again you must use ReDim to Allocate memory.
Let’s have a look an example for the static array. This example is the same as the
ArrayLoops example in the last section with one di�erence – we use Erase after setting
the values. When the value are printed out they will all be zero:
' https://excelmacromastery.com/
Public Sub EraseStatic()
' Print out the values - there are all now zero
Debug.Print "Location", "Value"
For i = LBound(arrMarks) To UBound(arrMarks)
Debug.Print i, arrMarks(i)
Next i
End Sub
We will now try the same example with a dynamic. After we use Erase all the locations in
the array have been deleted. We need to use ReDim if we wish to use the array again.
If we try to access members of this array we will get a “Subscript out of Range” error:
' https://excelmacromastery.com/
Public Sub EraseDynamic()
End Sub
In the following example, the second ReDim statement will create a completely new
array. The original array and its contents will be deleted.
' https://excelmacromastery.com/
Sub UsingRedim()
ReDim arr(0 To 2)
arr(0) = "Apple"
End Sub
If we want to extend the length of an array without losing the contents, we can use the
Preserve keyword.
When we use Redim Preserve the new array must start at the same starting dimension
e.g.
In the following code we create an array using ReDim and then �ll the array with types
of fruit.
We then use Preserve to extend the length of the array so we don’t lose the original
contents:
' https://excelmacromastery.com/
Sub UsingRedimPreserve()
End Sub
You can see from the screenshots below, that the original contents of the array have
been “Preserved”.
Word of Caution: In most cases, you shouldn’t need to resize an array like we have
done in this section. If you are resizing an array multiple times then you may want to
consider using a Collection.
For example, if you have a two-dimensional array you can only preserve the second
dimension as this example shows:
' https://excelmacromastery.com/
Sub Preserve2D()
End Sub
If we try to use Preserve on a lower bound we will get the “Subscript out of range” error.
In the following code we use Preserve on the �rst dimension. Running this code will give
the “Subscript out of range” error:
' https://excelmacromastery.com/
Sub Preserve2DError()
End Sub
The same Preserve rules apply. We can only use Preserve on the upper bound as this
example shows:
' https://excelmacromastery.com/
Sub Preserve2DRange()
arr = Sheet1.Range("A1:A5").Value
End Sub
' https://excelmacromastery.com/
Sub QuickSort(arr As Variant, first As Long, last As Long)
vTemp = arr(lTempLow)
arr(lTempLow) = arr(lTempHi)
arr(lTempHi) = vTemp
End If
Loop
End Sub
' https://excelmacromastery.com/
Sub TestSort()
End Sub
Passing to the procedure using ByRef means you are passing a reference of the array.
So if you change the array in the procedure it will be changed when you return.
Note: When you use an array as a parameter it cannot use ByVal, it must use ByRef. You
can pass the array using ByVal making the parameter a variant.
' https://excelmacromastery.com/
' Passes array to a Function
Public Sub PassToProc()
Dim arr(0 To 5) As String
' Pass the array to function
UseArray arr
End Sub
The main reason for returning an array is when you use the procedure to create a new
one. In this case you assign the return array to an array in the caller. This array cannot
be already allocated. In other words you must use a dynamic array that has not been
allocated.
' https://excelmacromastery.com/
Public Sub TestArray()
End Sub
End Function
One small thing to note is that Excel treats a one-dimensional array as a row if you write
it to a spreadsheet. In other words, the array arr(1 to 5) is equivalent to arr(1 to 1, 1 to 5)
when writing values to the spreadsheet.
The following image shows two groups of data. The �rst is a one-dimensional layout and
the second is two dimensional.
To access an item in the �rst set of data(1 dimensional) all you need to do is give the row
e.g. 1,2, 3 or 4.
For the second set of data (two-dimensional), you need to give the row AND the column.
So you can think of 1 dimensional being multiple columns and one row and two-
dimensional as being multiple rows and multiple columns.
Note: It is possible to have more than two dimensions in an array. It is rarely required. If
you are solving a problem using a 3+ dimensional array then there probably is a better
way to do it.
The following example creates a random value for each item in the array and the prints
the values to the Immediate Window:
' https://excelmacromastery.com/
Public Sub TwoDimArray()
Next j
Next i
End Sub
You can see that we use a second For loop inside the �rst loop to access all the items.
• j is set to 0
• j is set to 1
• j is set to 2
• And so on until i=3 and j=2
You may notice that LBound and UBound have a second argument with the value 2.
This speci�es that it is the upper or lower bound of the second dimension. That is the
start and end location for j. The default value 1 which is why we do not need to specify it
for the i loop.
Let’s take the code from above that writes out the two-dimensional array
Now let’s rewrite it using a For each loop. You can see we only need one loop and so it is
much easier to write:
Using the For Each loop gives us the array in one order only – from LBound to UBound.
Most of the time this is all you need.
' https://excelmacromastery.com/
Public Sub ReadToArray()
End Sub
The dynamic array created in this example will be a two dimensional array. As you can
see we can read from an entire range of cells to an array in just one line.
The next example will read the sample student data below from C3:E6 of Sheet1 and
print them to the Immediate Window:
' https://excelmacromastery.com/
Public Sub ReadAndDisplay()
End Sub
As you can see the �rst dimension(accessed using i) of the array is a row and the second
is a column. To demonstrate this take a look at the value 44 in E4 of the sample data.
This value is in row 2 column 3 of our data. You can see that 44 is stored in the array at
StudentMarks(2,3).
You can see more about using arrays with ranges in this YouTube video
In the last section, you saw how we can easily read from a group of cells to an array and
vice versa. If we are updating a lot of values then we can do the following:
For example, the following code would be much faster than the code below it:
' https://excelmacromastery.com/
Public Sub ReadToArray()
Dim i As Long
For i = LBound(StudentMarks) To UBound(StudentMarks)
' Update marks here
StudentMarks(i, 1) = StudentMarks(i, 1) * 2
'...
Next i
End Sub
' https://excelmacromastery.com/
Sub UsingCellsToUpdate()
Dim c As Variant
For Each c In Range("A1:Z20000")
c.Value = ' Update values here
Next c
End Sub
Assigning from one set of cells to another is also much faster than using Copy and Paste:
The following comments are from two readers who used arrays to speed up their
macros
“A couple of my projects have gone from almost impossible and long to run into almost too
easy and a reduction in time to run from 10:1.” – Dane
“One report I did took nearly 3 hours to run when accessing the cells directly — 5 minutes
with arrays” – Jim
You can see more about the speed of Arrays compared to other methods in this
YouTube video.
To see a comparison between Find, Match and Arrays it is worth checking out this post
by Charles Williams.
Conclusion
The following is a summary of the main points of this post
1. Arrays are an e�cient way of storing a list of items of the same type.
2. You can access an array item directly using the number of the location which is known
as the subscript or index.
3. The common error “Subscript out of Range” is caused by accessing a location that
does not exist.
4. There are two types of arrays: Static and Dynamic.
5. Static is used when the length of the array is always the same.
6. Dynamic arrays allow you to determine the length of an array at run time.
7. LBound and UBound provide a safe way of �nd the smallest and largest subscripts of
the array.
8. The basic array is one dimensional. You can also have multidimensional arrays.
9. You can only pass an array to a procedure using ByRef. You do this like this: ByRef
arr() as long.
10. You can return an array from a function but the array, it is assigned to, must not be
currently allocated.
11. A worksheet with its rows and columns is essentially a two-dimensional array.
12. You can read directly from a worksheet range into a two-dimensional array in just
one line of code.
13. You can also write from a two-dimensional array to a range in just one line of code.
What’s Next?
Free VBA Tutorial If you are new to VBA or you want to sharpen your existing VBA skills
then why not try The Ultimate VBA Tutorial.
Related Training: Get full access to the Excel VBA training webinars.
(NOTE: Planning to build or manage a VBA Application? Learn how to build 10 Excel VBA
applications from scratch.)
312 Comments
← Older Comments
James on June 17, 2020 at 2:49 pm
Hello Paul,
I’m reading through your articles and I have one concern:
what’s the best solution:
1. array of UDTs,
2. colection of UDTs,
3. dictionary of UDTs,
4. collection of classes
5. dictionary of classes?
Let’s assume it is the big number of personal data with strings, numbers
and dates.
Thanks in advance.
Reply
I could see many Custom Toolbars with User de�ned functions in all of
your videos.
Can you please help to understand, how it was created..
Jothiboss S
Reply
Reply
-Paul
Reply
Best
Dick Harkins
Scottsdale Arizona
dharkins@staircasered.com
Reply
Reply
Try it out on a small sample and compare the time. This video
may help.
Reply
DestinationRange.Formula = SourceRange.Formula
DestinationRange.Style = SourceRange.Style
Reply
But since the range is dynamic, it can happen that sometimes it contains
only one cell, eg Range(“A1”). Then it will not return a 2-dimensional
array, but a single String.
The consequence is that the for-loop can not be used, since the variant
arr is not an array.
Maybe you can add this to your great guide, to make it even more
complete.
THANKS in advance,
Rien, Netherlands
Reply
Reply
Reply
Reply
1. why does this not work (the values in the range are 0 to 10):
Dim Numbers() As Integer
Numbers = Range(“A1:L12”).Value
2. why does this not work (the row/column sizes are identical):
Dim Numbers(0 to 11,0 to 11) As Variant
Numbers = Range(“A1:L12”).Value
Reply
Sub pike_test()
Dim dbArray() As Variant
dbArray = [{“apple”,”bannana”,”mango”}]
Range(“H1”).Resize(1, UBound(dbArray)).Value = dbArray
dbArray = [{1,”apple”;3,”bannana”;5,”mango”}]
Range(“H5”).Resize(UBound(dbArray, 1), UBound(dbArray, 2)).Value =
dbArray
dbArray = [{1,2,3;4,5,6;7,8,9}]
Range(“A10”).Resize(UBound(dbArray, 1), UBound(dbArray, 2)).Value =
dbArray
End Sub
Reply
Reply
arr = ( 1 to 100, 1 to 3)
arr = ws1.range(“A2:C100”)
Its this last line that I can’t �nd a solution to. Array to Range seems a lot
faster then going thru each element of the array and writing to a cell.
Thanks!
Reply
Reply
Thanks for your very helpful explanations on VBA arrays! They helped
me solve a problem I had been struggling with for a long time.
What I found confusing however, is the illustration of the di�erence
between 1D and 2D arrays in the “Using a Two-Dimensional VBA Array”
section. In the illustration the 1D array stretches over as many columns
as the 2D array, which is in contradiction to your explanation or at least
rather counter-intuitive.
Or maybe, as a VBA newbie, I got it all wrong …?
Reply
Reply
every cell. I �nally scrolled down and read the comments here.
“A 1D array is simply a 2D array with one row.” and the light bulb goes
on!
It’s treating rows in the range as rows in the array, so for each new row
in the range it starts reading the array again. I reset the array from
arr(24) to arr(24,0) and everything works.
Perfect timing, too. I just ran into this yesterday.
Reply
Reply
The following code will split the string into an array of three elements:
Dim s As String
s = “Red,Yellow,Green,Blue”
Reply
Reply
Dim s As String
s = “Red,Yellow,Green,Blue”
Similarly for the case of the variant array, is ReDim implicitly called?
Thank you.
Reply
Reply
Reply
Reply
Reply
Thanks
Reply
Reply
-Paul
Reply
-Phil
Reply
Reply
← Older Comments
●●●●●●●●●●●●●
Remember Me
» Register
» Lost your Password?
Designed by Elegant Themes | Powered by WordPress