JavaRush /Courses /Kotlin SELF /for: ranges a..b and iterating over characters in a strin...

for: ranges a..b and iterating over characters in a string

Kotlin SELF
Level 4, Lesson 3
Available

1. Why do we need for if we already have while?

Honestly, you can write almost anything with while… but sometimes it looks like trying to hammer a nail with a microscope: technically possible, but very awkward. for is for those situations where repetition goes over a pre-prepared “source of values”: a numeric range, a string, an array, a collection. In Kotlin, for is designed exactly for this: “iterate over something that can yield elements one by one.”

In a everyday analogy: while is “while there is food in the fridge, keep eating,” and for is “eat 5 candies” or “go through all the letters in a word.” In both cases you repeat actions, but in the second one it’s easier to describe the repetition without manually managing a counter.

2. for syntax: “for each … in …”

for reads almost like an English phrase: “for each element x from a source of values, do the body.” The general form is: for (item in source) { ... }. This is not magic and not a spell—it’s just very convenient syntax that hides the routine: take the next value, execute the body, move to the next one.

It’s important to get used to this idea right away: the loop variable (item, i, ch) is the “current value,” not a “counter variable that we must manually increment.” In for, the loop itself advances the iteration (for you), and that’s one reason the code ends up shorter and calmer.

The simplest example is iterating over a list of words (while we are not studying collections deeply yet, this is just a demonstration of the idea):

fun main() {
    val shoppingList = listOf("Milk", "Bananas", "Bread")

    for (item in shoppingList) {
        println(item)
    }
    // Milk
    // Bananas
    // Bread
}

3. Ranges a..b in for

A range a..b is a way to say: “take all numbers from a to b, inclusive.” And the key word here is inclusive. If you write 1..5, the values will be 1, 2, 3, 4, and 5—five steps total. This is the most common range when you need to repeat an action N times or go “from X to Y.”

In the Kotlin documentation, for is described as a loop that can iterate over ranges along with arrays and collections. This means that for (i in 1..10) is absolutely “native” Kotlin style, not some accidental trick.

Mini example: “take 5 steps”

Let’s make the most transparent example possible—just print the step number:

fun main() {
    for (i in 1..5) {
        println("Step $i")
    }
    // Step 1
    // Step 2
    // Step 3
    // Step 4
    // Step 5
}

Two things are important to notice here.

First, we do not write i = i + 1. The loop changes the variable i, and we just use the current i.

Second, the variable i inside the loop behaves like a val: it is created anew for each iteration as the “current value.” If you try to do i = i + 1, the compiler will complain, and that’s for the best: fewer ways to break the logic.

A small table about “inclusive”

To avoid stepping on rakes, it’s useful to fix this once:

Range Values inside How many iterations
1..1
1
1
1..3
1, 2, 3
3
2..5
2, 3, 4, 5
4

If you need “exactly N repetitions, starting from 1,” 1..N is almost always a good fit.

for as “repeat N times” without a manual counter

In previous lectures with while, we built the classic “counter”: declare var i = 1, check the condition, and increment i inside. That’s fine and sometimes necessary. But when the step is obvious and linear (1, 2, 3…), for makes the code more compact and readable: you literally see the boundaries right in the loop header.

In practical terms, this means: if a task sounds like “make 10 attempts,” “read 3 values,” “compute the sum from 1 to n,” then for will usually be your first candidate. It reduces the risk of an infinite loop because you can’t forget to increment a counter—there simply isn’t one.

Summation: sum from 1 to n

The sum of numbers from 1 to n is a teaching example not because we desperately need to add numbers in real life (although accounting might disagree), but because it trains three skills at once: an accumulator variable, a range, and careful boundary handling.

Let’s make a mini program: ask for n; if it is valid and n >= 1, compute the sum using for.

fun main() {
    print("Enter n (>= 1): ")
    val n = readln().trim().toIntOrNull()

    if (n != null && n >= 1) {
        var sum = 0
        for (x in 1..n) sum += x
        println("sum = $sum")
    } else {
        println("Invalid n")
    }
}

There is a small readability trick here: for (x in 1..n) sum += x can be written on one line because the loop body is a single statement. Kotlin allows this. But if you have 2–3 actions inside the loop, it’s better to use { } so you don’t turn the program into a “poem with no line breaks.”

How for (x in 1..n) “thinks”

Sometimes it’s easier for a beginner to understand a loop if you imagine it as a mechanism that repeats steps. The simplified logic of a range-based for looks like this (not Kotlin code, but “how it works conceptually”):

flowchart TD
    A[Loop start] --> B[Take the next value x from the range]
    B --> C{Is there a value?}
    C -- no --> D[Exit loop]
    C -- yes --> E[Execute loop body]
    E --> B

This fits well with the idea from the Kotlin documentation: for iterates over anything that provides elements via an iterator, and ranges compile to an optimized iteration.

4. downTo and step: direction and step size

In real tasks you sometimes need to go from the end (for example, print the last values first), sometimes you need to take every other element (for example, process only even positions), and sometimes you need both. Kotlin provides two very simple constructs for this: downTo for descending direction and step for the step size.

Let’s start with the simple case: a countdown.

fun main() {
    for (i in 5 downTo 1) {
        print("$i ")
    }
    // 5 4 3 2 1
}

When using downTo, both values are included in the range.

Now let’s add a step: “by 2.”

fun main() {
    for (i in 10 downTo 0 step 2) {
        print("$i ")
    }
    // 10 8 6 4 2 0
}

It’s convenient to read left to right: “Start from 10, go down to 0, step 2.”

5. Iterating over a string in for

Now to the most “human” part of the lecture: a string is text, and text consists of characters. Very often you want to go through a string and count something: how many spaces, how many digits, whether the text contains @, how many times the letter a appears (yes, this is already a mini detective story).

In Kotlin, you can iterate over a string directly in for: for (ch in text) { ... }. On each iteration, ch will have type Char, i.e., a single character. Even if you haven’t covered a separate lecture about Char yet, it’s enough to understand: it’s “one letter/digit/symbol.”

And importantly: for over a string is the same principle of “iterating a source of values,” it’s just that the source is a string. The Kotlin documentation emphasizes that for works with any object that has an iterator. A string is exactly such an object.

Print all characters one by one

fun main() {
    val word = "Kotlin"

    for (ch in word) {
        println(ch)
    }
    // K
    // o
    // t
    // l
    // i
    // n
}

Yes, this looks like “I’m printing letters one by one to feel like a 90s printer.” But the practical value is that now we can do checks and counts per character.

Counting: spaces and digits

Now we’ll build a small “Text Analyzer v0” (version zero-zero-zero-very-early): the program reads a string and counts how many spaces and how many digits it contains. We won’t use anything complex—just for, if, and a couple of counters.

To determine “is this a digit or not,” you can compare the character with the boundaries '0' and '9'. Characters can be compared because they have an order (by code points). For a beginner this sounds a bit strange, but in practice it works great for digit ranges and Latin letters.

fun main() {
    print("Enter a string: ")
    val text = readln()

    var spaces = 0
    var digits = 0

    for (ch in text) {
        if (ch == ' ') spaces += 1
        if (ch >= '0' && ch <= '9') digits += 1
    }

    println("Spaces: $spaces, digits: $digits")
}

If the user enters Kotlin 2.3, the output will be roughly like this:

// Enter a string: Kotlin 2.3
// Spaces: 1, digits: 2

Here we gradually arrive at a useful habit: for often goes together with “counters” (var) that you update conditionally.

6. How to choose: while, do-while, or for

Now comes an important idea that saves you from “the wrong loop.” Technically, many tasks can be solved with different loops. But good style is to choose the one that expresses the meaning best.

while and do-while are useful when the number of repetitions is unknown in advance: “repeat until the input is valid” or “keep trying until you guess.” And for is for when you can describe the source of steps in advance: a numeric range or a sequence of characters. The Kotlin documentation puts it plainly: for iterates over collections, arrays, ranges, and in general everything that provides an iterator.

A table for quick orientation:

Situation Usually reads better
Repeat while the condition is true
while
The action must be performed at least once
do-while
Iterate over numbers from a to b
for (i in a..b)
Iterate over all characters of a string
for (ch in text)

7. Typical mistakes when working with for

Mistake No. 1: expecting the range a..b “not to include b.”
This is probably the most common confusion after coming from some other languages, and also just due to inattention. In our course, we fix it strictly: .. includes both boundaries. If you want to print the numbers 1, 2, 3, 4, 5—write 1..5, and everything will be correct.

Mistake No. 2: trying to manually modify the loop variable inside for.
In for, the loop variable is the “current value,” not your personal toy. If you try to do i = i + 1, the compiler won’t allow it. And that’s good: you won’t break the step or make the loop unpredictable. If you need to control the step manually, that’s a candidate for while (but today we’re just memorizing the principle).

Mistake No. 3: using for for repeated input “until it’s entered correctly.”
Sometimes you want to write “we’ll ask for input 10 times and maybe we’ll get lucky.” But if the user enters it incorrectly, you either run out of attempts and end up with an invalid state, or you complicate the logic. For “repeat until a correct value,” while or do-while is more natural, which we have already covered.

Mistake No. 4: mixing different meanings in one counter variable.
For example, when you are simultaneously counting a sum, the number of digits, and the number of spaces, it’s easy to accidentally update the “wrong” counter. This is not a for problem; it’s a readability problem. A simple rule helps: one variable—one meaning. digits counts digits, spaces counts spaces, sum counts the sum, and there’s no need to turn x into a universal soldier.

Mistake No. 5: forgetting about empty strings and “nothing happens.”
If the user enters an empty string, for (ch in text) simply won’t execute even once—and that’s normal behavior (just like while when the condition is immediately false). The main thing is not to panic: the program did not break; it honestly found no characters to process.

1
Task
Kotlin SELF, level 4, lesson 3
Locked
Tower Floors
Tower Floors
1
Task
Kotlin SELF, level 4, lesson 3
Locked
Route Sum
Route Sum
1
Task
Kotlin SELF, level 4, lesson 3
Locked
Character numbering
Character numbering
1
Task
Kotlin SELF, level 4, lesson 3
Locked
String check
String check
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION