Question
Can Kotlin create a range that counts backward?
For example, can a loop such as this print values from 100 down to 1?
for (n in 100..1) {
println(n)
}
The expected output would begin with:
100
99
98
...
Short Answer
Kotlin's .. operator creates an ascending range, so 100..1 is empty and the loop does not run. To count downward, use downTo, optionally combined with step to skip values.
Concept
Kotlin ranges describe a sequence of values between two endpoints. The range operator, .., is designed for ascending ranges:
1..5
This includes 1, 2, 3, 4, and 5.
Because an ascending range starts at the left value and moves upward, this range has no values:
100..1
There is no way to start at 100, keep increasing, and arrive at 1. Kotlin therefore treats it as an empty range.
Use downTo when the values should decrease:
100 downTo 1
downTo creates a descending progression, including both endpoints. This matters whenever order is important—for example, processing recent items first, counting down a timer, or removing list items from the end.
Mental Model
Think of a range as directions for walking along numbered stairs.
1..5means: start on stair 1 and walk up until stair 5.5 downTo 1means: start on stair 5 and walk down until stair 1.5..1means: start at stair 5 and walk upward to reach stair 1. That destination is behind you, so there are no steps to take.
The operator you choose determines the direction of travel.
Syntax and Examples
Use downTo between two integer values:
for (n in 100 downTo 1) {
println(n)
}
Output begins with:
100
99
98
...
1
Both endpoints are included. The loop variable starts as 100, decreases by 1 on each iteration, and ends after printing 1.
Count backward with a larger step
Add step to control how far the loop moves each time:
for (n in 20 downTo 0 step 5) {
println(n)
}
Output:
20
15
10
5
0
step 5 means subtract 5 after each iteration.
Store the progression first
A descending progression can be assigned to a variable and reused:
val countdown = 10 downTo 1
for (number in countdown) {
println(number)
}
Step by Step Execution
Consider this loop:
for (n in 5 downTo 1 step 2) {
println(n)
}
Execution proceeds as follows:
5 downTo 1creates a descending progression whose bounds are 5 and 1.step 2says to decrease by 2 each time.- The first iteration assigns
5ton, so the program prints5. - The next value is
3, so it prints3. - The next value is
1, so it prints1. - The next calculated value would be
-1, which is below the ending bound of1. - The loop stops.
Output:
5
3
1
By contrast, this loop has zero iterations:
for (n in 5..1) {
println(n)
}
5..1 is an empty ascending range.
Real World Use Cases
Descending progressions are useful when a task naturally starts at a high value and moves lower.
- Countdown timers: display
10down to0before starting an action. - Reverse array processing: visit indexes from the last element to the first.
- Removing items by index: remove matching items from the end so earlier indexes do not shift before they are processed.
- Recent-first output: show newer numbered records before older ones.
- Retry attempts: report remaining attempts from a maximum value down to zero.
Example: printing an array in reverse order by its indexes:
val names = listOf("Ada", "Grace", "Linus")
for (index in names.lastIndex downTo 0) {
println(names[index])
}
Output:
Linus
Grace
Ada
Real Codebase Usage
In production Kotlin code, downTo is often used for index-based work where reverse order is required.
Remove list elements safely from the end
When removing by index, iterate backward. Removing from the front can cause later elements to shift left and be skipped.
val scores = mutableListOf(10, -1, 20, -5, 30)
for (index in scores.lastIndex downTo 0) {
if (scores[index] < 0) {
scores.removeAt(index)
}
}
println(scores) // [10, 20, 30]
Prefer collection operations when no index is needed
If you only want values in reverse order, a collection operation is often clearer than managing indexes manually:
val names = listOf("Ada", "Grace", "Linus")
names.asReversed().forEach { name ->
println(name)
}
Use downTo when you genuinely need an index, a numeric countdown, or precise control over the step size.
Common Mistakes
Expecting 100..1 to count backward
This code compiles, but prints nothing:
for (n in 100..1) {
println(n)
}
Use downTo instead:
for (n in 100 downTo 1) {
println(n)
}
Assuming the end value is excluded
downTo includes both bounds:
for (n in 3 downTo 1) {
print("$n ")
}
// 3 2 1
If you need to stop before 1, use 2 as the lower bound or use a condition that matches the intended result.
Using an invalid step direction
A descending progression needs a positive step amount:
// Incorrect: throws IllegalArgumentException
// for (n in 10 downTo 1 step -2) { }
Write step 2, not step -2:
for (n in 10 downTo 1 step 2) {
println(n)
}
Accessing an empty list with lastIndex downTo 0
For an empty list, lastIndex is -1. The progression -1 downTo 0 is empty, so a for loop is safe. However, do not access an element before checking that the list has one:
val items = emptyList<String>()
for (index in items.lastIndex downTo 0) {
println(items[index])
}
This loop simply does not run.
Comparisons
| Syntax | Direction | Endpoints included? | Typical use |
|---|---|---|---|
1..5 | Up | Yes | Iterate from a lower number to a higher number |
5 downTo 1 | Down | Yes | Count down or process indexes in reverse |
1 until 5 | Up | Start yes, end no | Iterate over valid indexes such as 0 until list.size |
5 downTo 1 step 2 | Down | Includes 5; includes 1 only if reached | Reverse iteration while skipping values |
.. and downTo both include their boundary values. until differs because it excludes its ending value.
For example:
println((0 until 3).toList()) // [0, 1, 2]
println((3 downTo 0).toList()) // [3, 2, 1, 0]
Cheat Sheet
// Ascending, inclusive
for (n in 1..5) { }
// Descending, inclusive
for (n in 5 downTo 1) { }
// Descending with a step of 2
for (n in 10 downTo 0 step 2) { }
// Ascending, end excluded
for (index in 0 until items.size) { }
// Reverse indexes of a list or array
for (index in items.lastIndex downTo 0) { }
Key rules:
start..endis ascending only.- If
start > end,start..endis empty. start downTo endis descending.downToincludes the start and end values.stepmust be a positive number.- Use
lastIndex downTo 0when you need reverse indexes.
FAQ
Does 100..1 work as a backward range in Kotlin?
No. It creates an empty ascending range, so a for loop over it does not execute. Use 100 downTo 1.
Does downTo include the final number?
Yes. 5 downTo 1 produces 5, 4, 3, 2, 1.
How do I count backward by two in Kotlin?
Use step:
for (n in 10 downTo 0 step 2) {
println(n)
}
Can I use downTo with list indexes?
Yes. A common pattern is:
for (index in items.lastIndex downTo 0) {
println(items[index])
}
Is downTo a range?
It is commonly used like a range, but Kotlin represents it as a descending numeric progression. For for loops, it behaves as the sequence of descending values you expect.
What should I use to reverse a collection when I do not need indexes?
Use a collection-oriented approach such as asReversed() or reversed(). Use downTo when you need numeric indexes or custom stepping.
Mini Project
Description
Build a simple launch countdown that prints the remaining seconds in reverse order. It demonstrates a descending Kotlin progression and a custom interval with step.
Goal
Print a countdown from 10 to 0, displaying only even-numbered seconds, followed by a launch message.
Requirements
Use a for loop with a descending progression.
Start at 10 and finish at 0.
Decrease the value by 2 on each iteration.
Print each remaining number of seconds.
Print Launch! after the countdown completes.
Keep learning
Related questions
Accessing Kotlin Extension Functions from Java
Learn how Kotlin extension functions are compiled and how to call them correctly from Java with clear examples and common pitfalls.
Add a Maven Repository URL in Gradle Kotlin DSL (build.gradle.kts)
Learn how to add Maven Central and a custom Maven repository URL in Gradle Kotlin DSL using build.gradle.kts syntax.
Allow HTTP and HTTPS in Android 9 Pie with Network Security Configuration
Learn how Android 9 Pie handles cleartext HTTP traffic and how to allow HTTP and HTTPS safely using network security config.