Цикл For Each… Next в VBA Excel, его синтаксис и описание отдельных компонентов. Примеры использования цикла For Each… Next.
Цикл For Each… Next в VBA Excel предназначен для выполнения блока операторов по отношению к каждому элементу из группы элементов (диапазон, массив, коллекция). Этот замечательный цикл применяется, когда неизвестно количество элементов в группе и их индексация, в противном случае, более предпочтительным считается использование цикла For…Next.
For Each element In group [ statements ] [ Exit For ] [ statements ] Next [ element ] |
В квадратных скобках указаны необязательные атрибуты цикла For Each… Next.
Компоненты цикла For Each… Next
Компонент | Описание |
---|---|
element | Обязательный атрибут в операторе For Each, необязательный атрибут в операторе Next. Представляет из себя переменную, используемую для циклического прохода элементов группы (диапазон, массив, коллекция), которая предварительно должна быть объявлена с соответствующим типом данных*. |
group | Обязательный атрибут. Группа элементов (диапазон, массив, коллекция), по каждому элементу которой последовательно проходит цикл For Each… Next. |
statements | Необязательный** атрибут. Операторы вашего кода. |
Exit For | Необязательный атрибут. Оператор выхода из цикла до его окончания. |
*Если цикл For Each… Next используется в VBA Excel для прохождения элементов коллекции (объект Collection) или массива, тогда переменная element должна быть объявлена с типом данных Variant, иначе цикл работать не будет.
**Если не использовать в цикле свой код, смысл применения цикла теряется.
Примеры циклов For Each… Next
Цикл для диапазона ячеек
На активном листе рабочей книги Excel выделите диапазон ячеек и запустите на выполнение следующую процедуру:
Sub test1() Dim element As Range, a As String a = «Данные, полученные с помощью цикла For Each… Next:» For Each element In Selection a = a & vbNewLine & «Ячейка « & element.Address & _ » содержит значение: « & CStr(element.Value) Next MsgBox a End Sub |
Информационное окно MsgBox выведет адреса выделенных ячеек и их содержимое, если оно есть. Если будет выбрано много ячеек, то полностью информация по всем ячейкам выведена не будет, так как максимальная длина параметра Prompt функции MsgBox составляет примерно 1024 знака.
Цикл для коллекции листов
Скопируйте следующую процедуру VBA в стандартный модуль книги Excel:
Sub test2() Dim element As Worksheet, a As String a = «Список листов, содержащихся в этой книге:» For Each element In Worksheets a = a & vbNewLine & element.Index _ & «) « & element.Name Next MsgBox a End Sub |
Информационное окно MsgBox выведет список наименований всех листов рабочей книги Excel по порядковому номеру их ярлычков, соответствующих их индексам.
Цикл для массива
Присвоим массиву список наименований животных и в цикле For Each… Next запишем их в переменную a. Информационное окно MsgBox выведет список наименований животных из переменной a.
Sub test3() Dim element As Variant, a As String, group As Variant group = Array(«бегемот», «слон», «кенгуру», «тигр», «мышь») ‘или можно присвоить массиву значения диапазона ячеек ‘рабочего листа, например, выбранного: group = Selection a = «Массив содержит следующие значения:» & vbNewLine For Each element In group a = a & vbNewLine & element Next MsgBox a End Sub |
Повторим ту же процедуру VBA, но всем элементам массива в цикле For Each… Next присвоим значение «Попугай». Информационное окно MsgBox выведет список наименований животных, состоящий только из попугаев, что доказывает возможность редактирования значений элементов массива в цикле For Each… Next.
Sub test4() Dim element As Variant, a As String, group As Variant group = Array(«бегемот», «слон», «кенгуру», «тигр», «мышь») ‘или можно присвоить массиву значения диапазона ячеек ‘рабочего листа, например, выделенного: group = Selection a = «Массив содержит следующие значения:» & vbNewLine For Each element In group element = «Попугай» a = a & vbNewLine & element Next MsgBox a End Sub |
Этот код, как и все остальные в этой статье, тестировался в Excel 2016.
Цикл для коллекции подкаталогов и выход из цикла
В этом примере мы будем добавлять в переменную a названия подкаталогов на диске C вашего компьютера. Когда цикл дойдет до папки Program Files, он добавит в переменную a ее название и сообщение: «Хватит, дальше читать не буду! С уважением, Ваш цикл For Each… Next.».
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Sub test5() Dim FSO As Object, myFolders As Object, myFolder As Object, a As String ‘Создаем новый FileSystemObject и присваиваем его переменной «FSO» Set FSO = CreateObject(«Scripting.FileSystemObject») ‘Извлекаем список подкаталогов на диске «C» и присваиваем ‘его переменной «myFolders» Set myFolders = FSO.GetFolder(«C:») a = «Папки на диске C:» & vbNewLine ‘Проходим циклом по списку подкаталогов и добавляем в переменную «a« ‘их имена, дойдя до папки «Program Files«, выходим из цикла For Each myFolder In myFolders.SubFolders a = a & vbNewLine & myFolder.Name If myFolder.Name = «Program Files» Then a = a & vbNewLine & vbNewLine & «Хватит, дальше читать не буду!» _ & vbNewLine & vbNewLine & «С уважением,» & vbNewLine & _ «Ваш цикл For Each... Next.« Exit For End If Next Set FSO = Nothing MsgBox a End Sub |
Информационное окно MsgBox выведет список наименований подкаталогов на диске C вашего компьютера до папки Program Files включительно и сообщение цикла о прекращении своей работы.
В результате работы программы будут выведены не только наименования подкаталогов, видимых при переходе в проводнике к диску C, но и скрытые и служебные папки. Для просмотра списка всех подкаталогов на диске C, закомментируйте участок кода от If до End If включительно и запустите выполнение процедуры в редакторе VBA Excel.
In this Article
- For Each Loop
- For Each: Basic Examples
- Loop Through Cells
- Loop Through Sheets
- Loop Through Workbooks
- Loop Through Shapes
- Loop Through Charts
- Loop Through PivotTables
- Loop Through Tables
- Loop Through Items in Array
- Loop Through Numbers
- For Each Loop Builder
- For Each – If
- For Each Cell in Range – If
- For Each Common Examples
- Close All Workbooks
- Hide All Sheets
- Unhide All Sheets
- Protect All Sheets
- Unprotect All Sheets
- Delete All Shapes On All Worksheets
- Refresh All PivotTables
- Using For Each in Access VBA
This tutorial will show you examples of using the For Each Loop in VBA. Click here to learn more about loops in general.
For Each Loop
The For Each Loop allows you to loop through each object in a collection:
- All cells in a range
- All worksheets in a workbook
- All open workbooks
- All shapes in a worksheet
- All items in an array
- and more!
For Each: Basic Examples
These examples will demonstrate how to set up For Each loops to loop through different types of objects.
Loop Through Cells
This procedure will loop through each cell in range A1:A10, setting the cell to it’s right equal to itself.
Sub ForEachCell()
Dim Cell As Range
For Each Cell In Sheets("Sheet1").Range("A1:A10")
Cell.Offset(0, 1).value = Cell.value
Next Cell
End Sub
Loop Through Sheets
This procedure will loop through each sheet in a Workbook, unhiding each sheet.
Sub ForEachSheets()
Dim ws As Worksheet
For Each ws In Sheets
ws.Visible = True
Next ws
End Sub
Loop Through Workbooks
This procedure will loop through each Workbook, closing each one.
Sub ForEachWorkbooks()
Dim wb As Workbook
For Each wb In Workbooks
wb.Close
Next wb
End Sub
Loop Through Shapes
This procedure will loop through each shape in Sheet1, deleting each one.
Sub ForEachShape()
Dim Shp As Shape
For Each Shp In Sheets("Sheet1").Shapes
Shp.Delete
Next Shp
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!
Learn More
Loop Through Charts
This procedure will loop through each Chart in Sheet1, deleting each one.
Sub ForEachCharts()
Dim cht As ChartObject
For Each cht In Sheets("Sheet1").ChartObjects
cht.Delete
Next cht
End Sub
Loop Through PivotTables
This procedure will loop through each PivotTable in Sheet1, clearing each one
Sub ForEachPivotTables()
Dim pvt As PivotTable
For Each pvt In Sheets("Sheet1").PivotTables
pvt.ClearTable
Next pvt
End Sub
Loop Through Tables
This procedure will loop through each Table in Sheet1, deleting each one.
Sub ForEachTables()
Dim tbl As ListObject
For Each tbl In Sheets("Sheet1").ListObjects
tbl.Delete
Next tbl
End Sub
VBA Programming | Code Generator does work for you!
Loop Through Items in Array
This procedure will loop through each item in an Array, display each value in a msgbox,
Sub ForEachItemInArray()
Dim arrValue As Variant
Dim Item As Variant
arrValue = Array("Item 1", "Item 2", "Item 3")
For Each Item In arrValue
MsgBox Item
Next Item
End Sub
Loop Through Numbers
This procedure will loop through each number in an Array, display each value in a msgbox,
Sub ForEachNumberInNumbers()
Dim arrNumber(1 To 3) As Integer
Dim num As Variant
arrNumber(1) = 10
arrNumber(2) = 20
arrNumber(3) = 30
For Each num In arrNumber
Msgbox num
Next num
End Sub
For Each Loop Builder
The examples in this article were built with the Loop Builder in our VBA Add-in: AutoMacro.
The Loop Builder makes it very easy to generate code to loop through objects. AutoMacro also contains many other Code Generators, an extensive Code Library, and powerful Coding Tools.
For Each – If
You can also use If Statements within Loops to test if objects meet certain criteria, only performing actions on those objects that meet the criteria. Here is an example of looping through each cell in a range:
For Each Cell in Range – If
Sub If_Loop()
Dim Cell as Range
For Each Cell In Range("A2:A6")
If Cell.Value > 0 Then
Cell.Offset(0, 1).Value = "Positive"
ElseIf Cell.Value < 0 Then
Cell.Offset(0, 1).Value = "Negative"
Else
Cell.Offset(0, 1).Value = "Zero"
End If
Next Cell
End Sub
AutoMacro | Ultimate VBA Add-in | Click for Free Trial!
For Each Common Examples
Close All Workbooks
This procedure will close all open workbooks, saving changes.
Sub CloseAllWorkbooks()
Dim wb As Workbook
For Each wb In Workbooks
wb.Close SaveChanges:=True
Next wb
End Sub
Hide All Sheets
This procedure will hide all worksheets.
Sub HideAllSheets()
Dim ws As Worksheet
For Each ws In Sheets
ws.Visible = xlSheetHidden
Next ws
End Sub
Unhide All Sheets
This procedure will unhide all worksheets.
Sub UnhideAllSheets()
Dim ws As Worksheet
For Each ws In Sheets
ws.Visible = xlSheetVisible
Next ws
End Sub
AutoMacro | Ultimate VBA Add-in | Click for Free Trial!
Protect All Sheets
This procedure will protect all worksheets.
Sub ProtectAllSheets()
Dim ws As Worksheet
For Each ws In Sheets
ws.Protect Password:="..."
Next ws
End Sub
Unprotect All Sheets
This procedure will unprotect all worksheets.
Sub UnprotectAllSheets()
Dim ws As Worksheet
For Each ws In Sheets
ws.Unprotect Password:="..."
Next ws
End Sub
Delete All Shapes On All Worksheets
This procedure will delete all shapes in a workbook.
Sub DeleteAllShapesOnAllWorksheets()
Dim Sheet As Worksheet
Dim Shp As Shape
For Each Sheet In Sheets
For Each Shp In Sheet.Shapes
Shp.Delete
Next Shp
Next Sheet
End Sub
Refresh All PivotTables
This procedure will refresh all PivotTables on a sheet.
Sub RefreshAllPivotTables()
Dim pvt As PivotTable
For Each pvt In Sheets("Sheet1").PivotTables
pvt.RefreshTable
Next pvt
End Sub
Using For Each in Access VBA
The For Each loop works the same way in Access VBA as it does in Excel VBA. The following example will remove all the tables in the current database.
Sub RemoveAllTables()
Dim tdf As TableDef
Dim dbs As Database
Set dbs = CurrentDb
For Each tdf In dbs.TableDefs
DoCmd.DeleteObject tdf.Name
Loop
Set dbs = Nothing
End Sub
This is one of those things that I’m sure there’s a built-in function for (and I may well have been told it in the past), but I’m scratching my head to remember it.
How do I loop through each row of a multi-column range using Excel VBA? All the tutorials I’ve been searching up seem only to mention working through a one-dimensional range…
asked Sep 22, 2009 at 23:53
1
Dim a As Range, b As Range
Set a = Selection
For Each b In a.Rows
MsgBox b.Address
Next
answered Sep 23, 2009 at 0:19
MikeMike
2,9751 gold badge18 silver badges14 bronze badges
0
Something like this:
Dim rng As Range
Dim row As Range
Dim cell As Range
Set rng = Range("A1:C2")
For Each row In rng.Rows
For Each cell in row.Cells
'Do Something
Next cell
Next row
answered Sep 22, 2009 at 23:58
David AndresDavid Andres
31.2k7 gold badges45 silver badges36 bronze badges
1
Just stumbled upon this and thought I would suggest my solution. I typically like to use the built in functionality of assigning a range to an multi-dim array (I guess it’s also the JS Programmer in me).
I frequently write code like this:
Sub arrayBuilder()
myarray = Range("A1:D4")
'unlike most VBA Arrays, this array doesn't need to be declared and will be automatically dimensioned
For i = 1 To UBound(myarray)
For j = 1 To UBound(myarray, 2)
Debug.Print (myarray(i, j))
Next j
Next i
End Sub
Assigning ranges to variables is a very powerful way to manipulate data in VBA.
answered Dec 9, 2015 at 1:33
tc_NYCtc_NYC
1921 gold badge2 silver badges11 bronze badges
1
In Loops, I always prefer to use the Cells
class, using the R1C1 reference method, like this:
Cells(rr, col).Formula = ...
This allows me to quickly and easily loop over a Range of cells easily:
Dim r As Long
Dim c As Long
c = GetTargetColumn() ' Or you could just set this manually, like: c = 1
With Sheet1 ' <-- You should always qualify a range with a sheet!
For r = 1 To 10 ' Or 1 To (Ubound(MyListOfStuff) + 1)
' Here we're looping over all the cells in rows 1 to 10, in Column "c"
.Cells(r, c).Value = MyListOfStuff(r)
'---- or ----
'...to easily copy from one place to another (even with an offset of rows and columns)
.Cells(r, c).Value = Sheet2.Cells(r + 3, 17).Value
Next r
End With
answered Aug 20, 2015 at 16:50
LimaNightHawkLimaNightHawk
6,5033 gold badges40 silver badges60 bronze badges
0
The art of Excel VBA programming is in the manipulation of properties of objects of Excel. The more skillfully you can play with these objects and properties, the more powerful the macros you can build.
The number one object in Excel you have to process is by far the Range object. In this article, I am going to walk you through the critical skills to loop through ranges in Excel worksheets.
Loop through cells in a range
The main skill to loop through a range is with FOR-NEXT loops. There are two FOR-NEXT loop conventions, which are both very useful when we loop through ranges. I would highly recommend to learn both skills.
Method 1: with a range variable
In the Range object, there are many Cell objects. We can therefore think of a Range as a group of Cells. We can effectively use the “For Each element In group” convention of the For-Next statement to loop through every Cell inside a Range.
The macro LoopCells1 loops through every cell in Range “A1:C5” and applies a sequential counter into the content of each cell.
Sub LoopCells1() Dim cell As Range Dim counter As Integer 'loop through each cell object element within a range For Each cell In Range("A1:C5").Cells counter = counter + 1 'denotes the nth cell cell.Value = counter Next End Sub
The result after running the macro looks like this:
Method 2: with a numeric variable
Most VBA users are more confident with the For-Next loop convention of:
For counter = start To end
This convention can also be used to loop through cells within a range. The macro “LoopCells2” demonstrates how to loop through each cell in range A1:C5 by referring to the index number of cells. The loop begins with the index number of 1 to the upper bound which is the total number of cells in the range.
Sub LoopCells2() Dim c As Long Dim counter As Integer 'loop through each cell within a range by calling the index number of the cells For c = 1 To Range("A1:C5").Cells.Count 'put the index number into cell Range("A1:C5").Cells(c).Value = c Next End Sub
The result after running the macro “LoopCells2” looks identical to the result of the previous macro “LoopCells1”.
Important note on numeric variable type
One limitation of this method is with the upper limit of the numeric variable being declared and used in the For-Next loop. There are a few points you need to bear in mind:
- Avoid declaring an Integer typing variable for this purpose because the number of cells in a worksheet is far more than 32,767.
- Declare a Long variable instead, so that the loop can process up to 2,147,483,648 cells, which serves most cases.
- Declaring a Double variable type won’t solve the limitation.
- In case your process exceeded the limit of even a long variable, you will have to restructure your For-Next loop to use the “For Each element In group” convention.
But even with such limitations, this is still a very useful method. It’s often used because, in most situations, the limits of the variable type won’t be reached.
Note on order of cells being processed
When using either of the two methods above, the cells in the range are being processed in the same sequence: from left to right, then from top to bottom. The picture below visualizes such sequence:
If you want the cells to be processed in a different order, you need to learn other strategies which will be explained in the next few sections.
Loop through rows or columns in a range
Sometimes we want to loop through each row in a range (from top to bottom). Similar to looping through cells, we can do it with both conventions of the For-Next statement, either with a range object variable or a numeric variable.
Method 1: with a range variable
Sub LoopRows1() Dim r As Range Dim MyString As String 'Loop through each row, and apply a yellow colow fill For Each r In Range("A1:C5").Rows r.Interior.ColorIndex = 6 Next End Sub
To loop through columns, we just need to change the first line of the For-Next loop to go through the columns instead. In the example below, we want to loop through each column in range A1:C5, and change the column heading to Proper Case (first letter of each word in capital).
Sub LoopColumn1() Dim c As Range Dim MyString As String 'Loop through each column and set first cell to Proper Case For Each c In Range("A1:C5").Columns c.Cells(1).Value = StrConv(c.Cells(1).Value, vbProperCase) Next End Sub
Method 2: with a numeric variable
In this example, we want to loop through every column in a data table. (See picture of our sample data below.) If a column contains numeric data, we set the NumberFormat to 2 decimal places.
'apply 0.00 number format to columns with numeric values Sub FormatNumericColumns() Dim c As Integer Dim MyString As String With Range("A1").CurrentRegion For c = 1 To .Columns.Count 'test 2nd cell of column for numeric value If IsNumeric(.Columns(c).Cells(2).Value) Then .Columns(c).NumberFormat = "0.00" End If Next End Sub
The result of the macro looks like the image below. The number format of the last 3 columns with numeric data has been set to 2 decimal places.
(The dates in the first column are not considered by the VBA IsNumeric function as numeric. Please read my other article all about IsNumeric for more detail on this topic.)
Advanced strategies
Deleting columns (or rows)
Here we want to write a macro to delete the three columns with headings with the word “delete” (the yellow columns). We can tackle this problem with a For-Next loop we learned in the sections above.
First Attempt:
We can try to loop through each column with the “For Each element In group” convention. The macro below looks simple and straight-forward enough, looping through each column (element) within the group of columns in range A1:C5.
Sub DeleteColmns1() Dim c As Range Dim x As Integer With Range("A1:E5") For Each c In .Columns If c.Cells(1).Value = "delete" Then c.Delete End If Next End With End Sub
The result of the macro looks like the picture below. The macro has failed to delete all the three columns.
Reminder: When looping through a range, if you want to apply structural change to the range, NEVER use the “For Each element In group” convention because it may create unexpected results. In some cases, (e.g. insert columns), it will even cause an infinite loop and your Excel may be frozen and you’ll have to force quit Excel and lose your unsaved work.
Second Attempt:
Now, how about using the “For counter = start To end” convention?
Sub DeleteColmns2() Dim tmp As Integer Dim x As Integer With Range("A1:E5") For x = 1 To .Columns.Count If .Columns(x).Cells(1).Value = "delete" Then .Columns(x).Delete End If Next End With End Sub
The result looks identical to that of the previous macro:
If we looked at the result more carefully, we noticed that the original 2nd and 4th column were deleted, but the original 3rd column was not. This was because when the 2nd column was deleted (when x=2), the 3rd column has become the 2nd column which has been skipped when the For-Next loop proceed to process x = 3.
Solution:
So, how do we tackle this problem? The answer is with the For-Next statement convention of “For counter = end To start step -1″, which processes the range from back to front (from the last column backward to the first column).
Sub DeleteColumnFinal() Dim x As Integer With Range("A1").CurrentRegion For x = .Columns.Count To 1 Step -1 If .Columns(x).Cells(1).Value = "delete" Then .Columns(x).Delete End If Next End With End Sub
Loop though every n-th row in a range
We have a data table, and we want to apply a yellow shading (fill) to the odd number rows. And we don’t want to shade the first row which contains the field headings.
Solution 1:
We can use the “For counter = start To end” convention to tackle this problem. We can loop through each row beginning from the 2nd row (which bypassed the field headings). If the row number is odd, we apply a yellow color.
'Shade alternate (even) rows of data Sub ShadeRows1() Dim r As Long With Range("A1").CurrentRegion For r = 1 To .Rows.Count If r / 2 = Int(r / 2) Then 'even rows .Rows(r).Interior.ColorIndex = 6 End If Next End With End Sub
To enhance the macro to shade every n-th row, simply change the 2 in line 5 to n. For example:
If r / 3 = Int(r / 3) Then 'every 3 rows
Solution 2:
We can also use the “For counter = start to end step 2” convention. In the macro “ShadeRows2”, the loop begins from the 2nd row and then the 4th row, then 6th row, etc.
'Shade alternate (odd) rows of data from the 3rd row Sub ShadeRows2() Dim r As Long With Range("A1").CurrentRegion 'begin from 2nd and shade every other row For r = 2 To .Rows.Count Step 2 .Rows(r).Interior.ColorIndex = 6 Next End With End Sub
To enhance the macro to shade every 3rd row, simple change the 2 in line 5 to 3. For example:
For r = 3 To .Rows.Count Step 3
Conclusion
We have gone through in detail the different approaches to loop through a range in VBA, including the pitfalls and a couple of special scenarios. These techniques can also be applied in combination or with other VBA techniques to achieve more powerful automation with worksheet ranges in your macros.
This post provides a complete guide to the standard VBA For Loop and the VBA For Each Loop.
If you are looking for information about the VBA While and VBA Do Loop then go here.
If you want some quick info about the For loops then check out the Quick Guide table in the section below.
If you are looking for information on a particular topic then check out the Table of Contents below.
“History is about loops and continuums” – Mike Bidlo.
Related Links for the VBA For Loop
The Complete Guide to Ranges in Excel VBA.
The Complete Guide to Copying Data in Excel VBA.
VBA Do While Loop.
A Quick Guide to the VBA For Loop
Loop format | Description | Example |
---|---|---|
For … Next | Run 10 times | For i = 1 To 10 Next |
For … Next | Run 5 times. i=2,4, 6 etc. | For i = 2 To 10 Step 2 Next |
For … Next | Run in reverse order | For i = 10 To 1 Step -1 Debug.Print i Next |
For … Next | Go through Collection | For i = 1 To coll.Count Debug.Print coll(i) Next |
For … Next | Go through array | For i = LBound(arr) To UBound(arr) Debug.Print arr(i) Next i |
For … Next | Go through 2D array | For i = LBound(arr) To UBound(arr) For j = LBound(arr,2) To UBound(arr,2) Debug.Print arr(i, j) Next j Next i |
For Each … Next | Go through Collection | Dim item As Variant For Each item In coll Debug.Print item Next item |
For Each … Next | Go through array | Dim item As Variant For Each item In arr Debug.Print item Next item |
For Each … Next | Go through 2D array | Dim item As Variant For Each item In arr Debug.Print item Next item |
For Each … Next | Go through Dictionary | Dim key As Variant For Each key In dict.Keys Debug.Print key, dict(key) Next key |
Both types | Exit Loop | For i = 1 To 10 If Cells(i,1) = «found» Then Exit For End If Next i |
The VBA For Loop Webinar
If you are a member of the website, click on the image below to view the webinar for this post.
(Note: Website members have access to the full webinar archive.)
Introduction to the VBA For Loop
Loops are by far the most powerful component of VBA. They are the rocket fuel of your Macros. They can perform tasks in milliseconds that would take humans hours. They also dramatically reduce the lines of code your applications need.
For Loops have been part of all major programming languages since they were first used with Fortan in 1957.
If you have never used loops before then this post is a great place to start. It provides an in-depth guide to loops, written in plain English without the jargon.
Let’s start with a very important question – what are loops and why do we need them?
What are VBA For Loops?
A loop is simply a way of running the same lines of code a number of times. Obviously running the same code over and over would give the same result.
So what is important to understand is that the lines of code normally contain a variable that changes slightly each time the loop runs.
For example, a loop could write to cell A1, then cell A2, A3 and so on. The slight change each time is the row.
Let’s look at a simple example.
VBA For Loop Example 1
The following code prints the values 1 to 5 in the Immediate Window(Ctrl + G to view).
Debug.Print 1 Debug.Print 2 Debug.Print 3 Debug.Print 4 Debug.Print 5
The Immediate Window
If you have not used the Immediate Window before then this section will get you up to speed quickly.
The function Debug.Print writes values to the Immediate Window. To view this window select View->Immediate Window from the menu( the shortcut is Ctrl + G)
VBA For Loop Example 2
Now imagine we want to print out the numbers 1 to 20. We would need to add 15 more lines to the example above.
However, using a loop we only need to write Debug.Print once.
For i = 1 To 20 Debug.Print i Next i
The output is:
Output
If we needed print the numbers 1 to 1000 then we only need to change the 20 to 1000.
Normally when we write code we would use a variable instead of a number like 20 or 1000. This gives you greater flexibility. It allows you to decide the number of times you wish to run the loop when the code is running. The following example explains this.
VBA For Loop Example 3
A common task in Excel is read all the rows with with data.
The way you approach this task is as follows
- Find the last row with data
- Store the value in variable
- Use the variable to determine how many times the loop runs
Using a variable in the loop makes your code very flexible. Your will work no matter how many rows there are.
Let’s have a look at an example. Imagine you receive a sheet with a list of fruit types and their daily sales. You want to count the number of Oranges sold and this list will vary in size depending on sales.
The following screenshot shows an example of this list
Sample Data of Fruit Sales
We can use the code to count the oranges
' https://excelmacromastery.com/ Sub CountFruit() ' Get the last row with text Dim LastRow As Long LastRow = Sheet1.Cells(Sheet1.Rows.Count, 1).End(xlUp).Row Dim i As Long, Total As Long ' Use LastRow in loop For i = 2 To LastRow ' Check if cell has text "Orange" If Sheet1.Cells(i, 1).Value = "Oranges" Then ' Add value in column B to total Total = Total + Sheet1.Cells(i, 2).Value End If Next i ' Print total Debug.Print "Total oranges sold was:"; Total End Sub
You can try this code for yourself. Change the number of fruit items and you will see that the code still works fine.
If you were to increase the number fruit items to a large value like 10,000 then you will hardly notice the difference in the time it takes to run – almost instantly.
Loops are super fast. This is what makes them so powerful. Imagine performing a manual task on 10,000 cells. It would take a considerable amount of time.
Advantages of the VBA For Loop
4To conclude this section we will list the major advantages of using loops
- They reduce the lines code you need
- They are flexible
- They are fast
In the next sections we will look at the different types of loops and how to use them.
The Standard VBA For Loop
The VBA For loop is the most common loop you will use in Excel VBA. The For Loop is used when you can determine the number of times it will be run. For example, if you want to repeat something twenty times.
YouTube Video For Loop
Check out this YouTube Video of the For Loop:
Get the workbook and code for this video here
Format of the Standard VBA For Loop
The Standard VBA For Loop has the following format:
For <variable> = <start value> to <end value>
Next <variable>
The start and end values can be variables. Also the variable after Next is optional but it is useful and it makes it clear which for loop it belongs to.
How a For Loop Works
Let’s look at a simple for loop that prints the numbers 1 to 3
Dim i As Long For i = 1 To 3 Debug.Print i Next i
How this code works is as follows
i is set to 1
The value of i(now 1) is printed
i is set to 2
The value of i(now 2) is printed
i is set to 3
The value of i(now 3) is printed
If we did not use a loop then the equivalent code would be
Dim i As Long i = i + 1 Debug.Print i i = i + 1 Debug.Print i i = i + 1 Debug.Print i
The i = i + 1 line is used to add 1 to i and is a common way in programming to update a counter.
Using Step with the VBA For Loop
You can see that i is increased by one each time. This is the default. You can specify this interval using Step keyword.
The next example shows you how to do this:
' Prints the even numbers i.e. 2,4,6,8 ... 20 For i = 2 To 20 Step 2 Debug.Print i Next i
You can use a negative number with Step which will count in reverse
' Prints the even numbers in reverse i.e. 20,18,16,14 ... 2 For i = 20 To 2 Step -2 Debug.Print i Next i
Note: if Step is positive then your starting number must be lower than you ending number. The following loop will not run because the starting number 20 is greater than 10. VBA therefore, thinks it has already reached the target value 10.
' Will not run as starting number already greater than 10 For i = 20 To 10 Step 1 Debug.Print i Next i
If Step is negative then the start number must be greater than the end number.
Exit the For Loop
Sometimes you may want to leave the loop earlier if a certain condition occurs. For example if you read bad data.
You can use Exit For to automatically leave the loop as shown in the following code
For i = 1 To 1000 ' If cell is blank then exit for If Cells(i, 1) = "" Then MsgBox "Blank Cell found - Data error" Exit For End If Next i
Using the VBA For Loop with a Collection
The For loop can also be used to read items in a Collection.
In the following example, we display the name of all the open workbooks
Dim i As Long For i = 1 To Workbooks.Count Debug.Print Workbooks(i).FullName Next i
Using Nested For Loops
Sometimes you may want to use a loop within a loop. An example of this would be where you want to print the names of the worksheets of each open workbook.
The first loop would go through each workbook. Each time this loop runs it would use a second loop to go through all the worksheets of that workbook. It is actually much easier to do than it sounds.
The following code shows how:
' https://excelmacromastery.com/ Sub ListWorksheets() Dim i As Long, j As Long ' First Loop goes through all workbooks For i = 1 To Workbooks.Count ' Second loop goes through all the worksheets of workbook(i) For j = 1 To Workbooks(i).Worksheets.Count Debug.Print Workbooks(i).Name + ":" + Worksheets(j).Name Next j Next i End Sub
This works as follows:
The first loop sets i to 1
The second loop then uses the workbook at 1 to go through the worksheets.
The first loop sets i to 2
The second loop then uses the workbook at 2 to go through the worksheets.
and so on
It the next section we will use a For Each loop to perform the same task. You will find the For Each version much easier to read.
The VBA For Each Loop
The VBA For Each loop is used to read items from a collection or an array. We can use the For Each loop to access all the open workbooks. This is because Application.Workbooks is a collection of open workbooks.
This is a simple example of using the For Each Loop
Dim wk As Workbook For Each wk In Workbooks Debug.Print wk.FullName Next wk
Format of the VBA For Each Loop
You can see the format of the VBA for each loop here(See Microsoft For Each Next documentation):
For Each <variable> in <collection>
Next <variable>
To create a For Each loop we need a variable of the same type that the collection holds. In the example here we created a variable of type Workbook.
If the collection has different types of items we can declare the variable as a variant.
VBA contains a collection called Sheets. This is a collection of sheets of type Worksheet(normal) and Chart(when you move a chart to be a full sheet). To go through this collection you would declare the variable as a Variant.
The following code uses For Each to print out the name of all the sheets in the current workbook
Dim sh As Variant For Each sh In ThisWorkbook.Sheets Debug.Print sh.Name Next sh
Order of Items in the For Loop
For Each goes through items in one way only.
For example, if you go through all the worksheets in a workbook it will always go through from left to right. If you go through a range it will start at the lowest cell e.g. Range(“A1:A10”) will return A1,A2,A3 etc.
This means if you want any other order then you need to use the For loop.
Both loops in the following example will read the worksheets from left to right:
' Both loops read the worksheets from left to right Dim wk As Worksheet For Each wk In ThisWorkbook.Worksheets Debug.Print wk.Name Next Dim i As Long For i = 1 To ThisWorkbook.Worksheets.Count Debug.Print ThisWorkbook.Worksheets(i).Name Next
As you can see the For Each loop is neater to write. However if you want to read the sheets in any other order e.g. right to left then you have to use the for loop:
' Reading the worksheets from right to left Dim i As Long For i = ThisWorkbook.Worksheets.Count To 1 Step -1 Debug.Print ThisWorkbook.Worksheets(i).Name Next
Using the VBA For Each Loop With Arrays
One thing to keep in my is that the For Each loop is that it is read-only when you use it with arrays.
The following example demonstrates this:
' https://excelmacromastery.com/ Sub UseForEach() ' Create array and add three values Dim arr() As Variant arr = Array("A", "B", "C") Dim s As Variant For Each s In arr ' Changes what s is referring to - not value of array item s = "Z" Next ' Print items to show the array has remained unchanged For Each s In arr Debug.Print s Next End Sub
In the first loop we try to assign s to “Z”. When happens is that s is now referring the string “Z” and no longer to the item in the array.
In the second loop we print out the array and you can see that none of the values have changed.
When we use the For Loop we can change the array item. If we change the previous code to use the For Loop you it will change all the array values to “Z”
' https://excelmacromastery.com/ Sub UsingForWithArray() ' Create array and add three values Dim arr() As Variant arr = Array("A", "B", "C") Dim i As Long For i = LBound(arr) To UBound(arr) ' Changes value at position to Z arr(i) = "Z" Next ' Print items to show the array values have change For i = LBound(arr) To UBound(arr) Debug.Print arr(i) Next End Sub
If your Collection is storing Objects the you can change the items using a For Each loop.
Using Nested For Each Loops
We saw already that you can have a loop inside other loops. Here is the example from above:
' https://excelmacromastery.com/ Sub ListWorksheets() Dim i As Long, j As Long ' First Loop goes through all workbooks For i = 1 To Workbooks.Count ' Second loop goes through all the worksheets of workbook(i) For j = 1 To Workbooks(i).Worksheets.Count Debug.Print Workbooks(i).Name + ":" + Worksheets(j).Name Next j Next i End Sub
This time we will use the For Each loop to perform the same task:
' https://excelmacromastery.com/ Sub ReadAllWorksheets() Dim wk As Workbook, sh As Worksheet ' Read each workbook For Each wk In Workbooks ' Read each worksheet in the wk workbook For Each sh In wk.Worksheets ' Print workbook name and worksheet name Debug.Print wk.Name + ": " + sh.Name Next sh Next wk End Sub
As you can see this is a neater way of performing this task than using the For Loop:
This code run as follows:
- Get the first Workbook from the Workbooks collection
- Go through all the worksheets in this workbook
- Print the workbook/worksheet details
- Get the next workbooks in the collection
- Repeat steps 2 to 3
- Continue until no more workbooks are left in the collection
How to Loop Through a Range
In Excel VBA, the most common use of a For Loop is to read through a range.
Imagine we have the data set in the screenshot below. Our task is to write code that will read through the data and copy the amounts to the column J. We are only going to copy amounts that are greater than 200,000.
The following example shows how we do it:
' Read through an Excel Range using the VBA For Loop ' https://excelmacromastery.com/ Sub ForLoopThroughRange() ' Get the worksheet Dim sh As Worksheet Set sh = ThisWorkbook.Worksheets("Sheet1") ' Get the Range Dim rg As Range Set rg = sh.Range("A1").CurrentRegion ' Delete existing output sh.Range("J1").CurrentRegion.ClearContents ' Set the first output row Dim row As Long row = 1 ' Read through all the rows using the For Loop Dim i As Long For i = 2 To rg.Rows.Count ' Check if amount is greater than 200000 If rg.Cells(i, 4).Value > 200000 Then ' Copy amount to column m sh.Cells(row, "J").Value = rg.Cells(i, 4).Value ' Move to next output row row = row + 1 End If Next i End Sub
This is a very basic example of copying data using Excel VBA. If you want a complete guide to copying data using Excel VBA then check out this post
Summary of the VBA For Loops
The Standard VBA For Loop
- The For loop is slower than the For Each loop.
- The For loop can go through a selection of items e.g. 5 to 10.
- The For loop can read items in reverse e.g. 10 to 1.
- The For loop is not as neat to write as the For Each Loop especially with nested loops.
- To exit a For loop use Exit For.
The VBA For Each Loop
- The For Each loop is faster than the For loop.
- The For Each loop goes through all items in the collectionarray.
- The For Each loop can go through items in one order only.
- The For Each loop is neater to write than a For Loop especially for nested loops.
- To exit a For Each loop use Exit For.
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 out the 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.)