To run a VBA For loop in reverse order, start the counter at the highest value, set the lowest value as the limit, and use Step -1. For example, For i = 10 To 1 Step -1 visits 10, 9, 8, and so on through 1.
Basic reverse-loop syntax
A VBA For...Next loop normally increases its counter by one. Add a negative step to make it count downward. The general pattern is:
For counter = startValue To endValue Step -1
' Run statements for this counter value.
Next counter
The starting value should be greater than or equal to the ending value. Both ends are included when the loop reaches them. If the loop starts at 5 and ends at 1, it runs five times: once for each integer from 5 down to 1. A small complete example is:
Sub CountBackward()
Dim i As Long
' Print the integers from 10 down to 1.
For i = 10 To 1 Step -1
Debug.Print i
Next i
End Sub
In the Visual Basic Editor, Debug.Print sends each value to the Immediate window. This example demonstrates the loop logic; it does not change worksheet data. For a macro that does change a workbook, save a copy first. Excel cannot undo macro actions with Ctrl+Z.
How Step -1 controls the loop
The Step expression determines how much the counter changes after each pass. A step of 1 moves upward by one, while a step of -1 moves downward by one. You can use other negative increments when the values call for them. For example, For i = 20 To 0 Step -5 visits 20, 15, 10, 5, and 0.
VBA checks the loop direction against the limit. With a negative step, the loop can run while the counter is at or above the ending value. If you accidentally use a starting value below the ending value with Step -1, the loop body does not run. For instance, For i = 1 To 10 Step -1 does not count upward; its direction and bounds do not match.
Use an integer variable such as Long for ordinary counts, row numbers, and array indexes. A Long can represent much larger values than VBA’s older Integer type, which matters when working with Excel row numbers. For a step that is a variable, make sure it is not zero: a zero step cannot move the counter toward the limit and can lead to an endless loop.
When counting backward is useful
Reverse loops are especially useful when each pass may remove or shift an item earlier in a sequence. If you delete rows from top to bottom, the remaining rows move up, and the next row number can point to a record you have already passed. Starting at the bottom avoids that shifting problem. Reverse traversal is also useful for processing the newest item first, reading an array from its final element, or undoing a sequence in reverse order.
Choose direction based on the work, not just on whether the data appears sorted. If the loop only reads values and does not modify the collection, either direction may be fine. If it deletes, inserts, or rearranges items, think through what happens to indexes after each change. A backward pass is a common, simple solution for deletions from indexed lists and worksheet rows, although it is not automatically the right choice for every operation.
Looping backward through worksheet rows
This macro checks column A from the last used row up to row 2, treating row 1 as a header, and deletes rows where column A contains the text Closed. It uses the first worksheet in the workbook containing the code. Change that worksheet reference and the tested column to match your layout. Save a copy of the workbook before running it; deleting rows with VBA cannot be reversed with Ctrl+Z.
Sub DeleteClosedRows()
Dim ws As Worksheet
Dim lastRow As Long
Dim i As Long
' Use the first worksheet in this workbook.
Set ws = ThisWorkbook.Worksheets(1)
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
' Start at the bottom so row deletions do not skip records.
For i = lastRow To 2 Step -1
If ws.Cells(i, 1).Value = "Closed" Then
ws.Rows(i).Delete
End If
Next i
End Sub
The End(xlUp) expression finds the last non-empty cell in column A by moving upward from the bottom of that worksheet column. If column A has blanks below the actual data, this still finds its last populated cell. If a different column is more reliable for identifying the final data row, use that column in both places where the code currently uses column number 1.
Starting at row 2 protects the header only if the sheet really has a header in row 1. If there is no header, set the lower limit to 1. Also consider whether the comparison should ignore capitalization or extra spaces; the simple equality test expects the cell value to match Closed. For important data, test on a duplicate sheet first and confirm the rows selected before using a deletion macro on the original.
Reversing an array or collection
For a fixed-size array, use its actual lower and upper bounds rather than assuming the first index is 1. VBA arrays can have different bounds, and arrays created with Array or declared with a custom range may not match an assumed index pattern. The loop below declares a one-based array and prints its values from last to first:
Sub ReadArrayBackward()
Dim values(1 To 4) As Long
Dim i As Long
' Fill the array with sample values.
values(1) = 12
values(2) = 24
values(3) = 36
values(4) = 48
For i = UBound(values) To LBound(values) Step -1
Debug.Print values(i)
Next i
End Sub
UBound returns the upper index, and LBound returns the lower index. Using both makes the loop clearer and less dependent on a particular array declaration. For a multidimensional array, specify the dimension when asking for its bounds, such as UBound(data, 2) for the second dimension. The loop must still use the bounds of the dimension being traversed.
A VBA For Each loop does not provide a reverse-order option or a Step clause. If you need to visit a collection backward, use its numeric indexes when the collection supports indexed access, beginning at its count and ending at its first valid index. For a standard VBA Collection, indexes ordinarily run from 1 through Count. Not every object collection behaves identically, so check its documentation and indexing rules.
Common mistakes and how to avoid them
- Leaving out the negative step:
For i = 10 To 1uses the default positive step, not a reverse step. WriteStep -1explicitly. - Reversing the bounds but not the step: A loop from a larger value to a smaller value needs a negative step. A mismatched direction usually means the body is skipped.
- Using the wrong lower limit: If worksheet data begins on row 2 because row 1 is a heading, end at 2. If it begins on row 1, ending at 2 leaves the first record untouched.
- Assuming an array starts at zero or one: Use
LBoundandUBoundunless the bounds are deliberately fixed and documented. - Changing the counter inside the loop: Avoid assigning a new value to the loop variable within the body. It makes the sequence hard to reason about and can cause skipped or repeated work.
- Forgetting that rows shift after deletion: Delete from the bottom upward so deleting a row does not move unprocessed rows into indexes the loop has already passed.
It is also worth checking what happens when there is no data below a header. In the worksheet example, if the last used row is 1, the loop has no qualifying row to process, so it does nothing. That is appropriate for a header-only sheet. If a macro has more complicated bounds or several dependent operations, add explicit checks and test empty, one-item, and typical cases.
Reverse For loops compared with alternatives
A reverse For loop is a good fit when the number of passes and index range are known. It makes the start, limit, and direction visible in one line. A forward For loop is often easier to read when processing data that is only being inspected or when operations do not change indexes. Do not reverse a loop just because its output needs to be displayed in reverse; another option is to collect results and present them in the desired order.
A Do While loop can also count backward, but the code must update the counter and maintain its stopping condition correctly. That flexibility is useful when the number of repetitions is not known in advance, but it creates more ways to forget an update or write a condition that never becomes false. When the bounds are known, For...Next usually communicates the intent more directly.
For large ranges in Excel, performance often depends more on how the macro reads and writes cells than on whether the loop counts upward or downward. Repeated worksheet access inside a loop can be slow compared with working with values in memory, but that approach adds complexity and should be chosen only when it suits the task. A reverse loop solves an ordering and index-shift problem; it is not, by itself, a general speed optimization.
Excel platform and macro safety notes
VBA macros run in the desktop versions of Excel for Windows and Mac, but Excel for the web cannot create or run VBA macros. The VBA editor and some object-model features can differ between Windows and Mac, so a macro that uses operating-system-specific components may need adjustments. The basic For...Next syntax and downward counting pattern are the same.
Only enable and run macros from sources you trust. A macro can alter or delete workbook content, and the normal Undo command does not restore those changes. Keep an untouched backup, test on a copy, and inspect the target worksheet and loop bounds before running code that edits cells or deletes rows.
Frequently Asked Questions
How do you write a reverse For loop in VBA?
Set the counter to the highest value, use the lowest value after To, and add Step -1. For example, For i = 5 To 1 Step -1 counts down from 5 to 1.
Does VBA include both the starting and ending numbers?
Yes. A For...Next loop includes a bound when the counter reaches it. A loop from 5 to 1 with a step of -1 includes both 5 and 1.
Why does my reverse VBA loop not run?
Check that the starting value is greater than or equal to the ending value and that the step is negative. A start below the limit with Step -1 does not form a downward range, so the loop body is skipped.
Can I use Step -2 or another negative number?
Yes. A negative step can be any appropriate nonzero amount. For example, For i = 10 To 0 Step -2 visits 10, 8, 6, 4, 2, and 0.
Should I loop backward when deleting Excel rows?
Usually, yes, when deleting rows one at a time by index. Begin at the last relevant row and move upward so deleting a row does not shift a not-yet-checked row past the loop. Test the macro on a copy first because deletion by VBA cannot be undone with Ctrl+Z.
Related
- Protect Excel Sheets in Teams: What It Does and How
- Python Goal Seek Like Excel? Methods and Examples
- Power BI Compare Two Excel Sheets: A Practical Guide
Try it: the Column Letter to Number: aA is 27, XFD is 16,384. Converts both ways.
More in VBA & macros
- Excel VBA: Show a UserForm When the Workbook OpensTo show an Excel VBA UserForm when a workbook opens, put a Workbook_Open event procedure in the ThisWorkbook…
- VBA Copy Paste Row: Excel Code and Common FixesTo copy an entire row to another row in Excel with VBA, use Rows(sourceRow).Copy Destination:=Rows(targetRow). For example, Worksheets("Data").Rows(5).Copy…
- Delete Rows From an Input Range in VBATo delete worksheet rows covered by a range you select in Excel VBA, use Application.InputBox with Type:=8, then…
- Excel VBA: Find the Last Cell with Data in a ColumnIn Excel VBA, use Cells(Rows.Count, columnNumber).End(xlUp).Row to find the last nonblank cell’s row in a column. Check for…
- Excel VBA UserForm: Bring It to the FrontTo bring a modeless Excel VBA UserForm forward on Windows, show it with vbModeless, then use the Windows…
- Excel VBA Worksheet Change Event Not Working? FixesIf an Excel VBA worksheet change event is not working, first check that the Worksheet_Change procedure is in…
Sources: Function behaviour and menu paths: Microsoft Support documentation for Excel. Method & sources
Spotted an error in this guide? Let us know.