Start learning free

LESSON 122 OF 348 · WHILE LOOPS & FOR LOOPS

Looping in Reverse in Kotlin with downTo

Lesson Read the full explanation

A for loop can also count backwards, as long as we define the right conditions. For example:

for (i in 7 downTo 3) {
	println(i)
}

The output of this code is:

7
6
5
4
3

Let's break down this code:

  • The initialization statement is int i = 7, so we start iterating from number 7.

  • We loop as long as i > 2, so we'll end at number 3. We could've written i >= 3 and it would still be correct.

  • The iteration statement is i--, so we decrease our number by 1 every time.


Assignment

Let's print all numbers from 5 through -5 in decreasing order.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 2
    Ctrl + Enter to check

    KOTLIN · WHILE LOOPS & FOR LOOPS

    Looping In Reverse in Kotlin, explained

    Counting down

    The .. and until operators only count upward, so a range such as 5..-5 is empty. To count backwards, Kotlin has downTo:

    for (i in 7 downTo 3) {
        println(i)
    }
    

    It prints:

    7
    6
    5
    4
    3
    

    a downTo b starts at a, decreases by 1 each time, and includes b. The larger number goes on the left, the smaller one on the right. Like .., downTo includes both ends, so there is no "down until" version to worry about: the last value printed is exactly the one on the right.

    What goes wrong with the wrong operator

    A loop that is meant to count down but uses .. does not fail. It silently does nothing:

    for (i in 5..-5) {
        println(i)
    }
    println("finished")
    

    This prints only finished, because the range from 5 up to -5 contains no numbers. If a reversed loop produces no output at all, check the direction first.

    Combining downTo with step

    You can skip values while counting down by adding step, with a positive number even though the direction is downward:

    for (i in 10 downTo 1 step 3) {
        println(i)
    }
    

    This prints 10, 7, 4 and 1. A negative step, such as step -3, throws an IllegalArgumentException because the direction is already decided by downTo.

    The exercise: print 5 down to -5

    The task is to print every number from 5 down to -5, in decreasing order, one per line. That is 11 numbers, because zero and both ends are included.

    1. Write the loop with the right progression. Use the variable i and 5 downTo -5. The start, 5, is the larger number, and the end, -5, is the smaller. Both appear in the output.
    2. Print the variable. The body is println(i), which prints one number per line.

    The solution in Kotlin

    for (i in 5 downTo -5) {
        println(i)
    }
    

    The output is 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, each on its own line.

    Details worth knowing

    • Negative numbers need no special handling. The loop passes through 0 and keeps going down. The progression is just a sequence of integers.
    • The result is a progression, not a loop keyword. 5 downTo -5 builds an IntProgression, an object holding the first value, the last value and the step. The for loop then walks through it. Printing (7 downTo 3).toList() gives [7, 6, 5, 4, 3].
    • Reversing an existing range. A range you already have can be flipped with reversed(): (3..7).reversed() visits 7, 6, 5, 4, 3, which is the same as 7 downTo 3.
    • Counting an array backwards. For an array nums, the valid indices run from nums.size - 1 down to 0, so for (i in nums.size - 1 downTo 0) visits every index from the back. The array also has a property nums.indices, and nums.indices.reversed() does the same.

    Why not just subtract in a while loop?

    You can also count down with a while loop: declare var i = 5, loop while i >= -5, print i and then do i--. It works, but you now own three pieces that must agree: the start, the condition and the update. Forget the i-- and the loop never ends; write i > -5 and the last number is lost. With 5 downTo -5 all of that is one expression, and the loop ends by itself when the values run out. Prefer the for form whenever you know the first and last value in advance.

    Reading the range aloud helps: 5 downTo -5 is "from 5 down to -5". If the larger number is on the left and the smaller on the right, the direction is right.

    Common mistakes

    • Using .. to count down. The loop body never runs.
    • Swapping the operands of downTo. -5 downTo 5 is also empty, since it asks to go down from -5 to 5, and there are no numbers that do so.
    • Stopping one early. Because the end is included, 5 downTo -5 prints -5. Writing 5 downTo -4 would lose it.
    • Using a negative step. Steps are always positive in Kotlin ranges. The direction comes from the operator.
    • Looking for a -- to write. There is no update statement to change. The progression handles the decrease.

    Key takeaways

    • a downTo b counts down from a to b by 1 and includes both ends.
    • a..b with a > b is empty and does not count down.
    • Add step with a positive number to skip values.
    • To print 5 through -5 in decreasing order: for (i in 5 downTo -5) { println(i) }.
    Keep going with KotlinAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free