JavaRush /Курсы /Kotlin SELF /for: диапазоны a..b и перебор символов строки

for: диапазоны a..b и перебор символов строки

Kotlin SELF
4 уровень , 3 лекция
Открыта

1. Зачем нужен for, если уже есть while?

Если честно, на while можно написать почти всё… но иногда это выглядит как попытка забить гвоздь микроскопом: технически возможно, но очень неловко. for нужен для тех ситуаций, когда повторение идёт по заранее подготовленному «источнику значений»: диапазону чисел, строке, массиву, коллекции. В Kotlin for прямо так и задуман: «перебирай то, что умеет отдавать элементы по очереди».

В бытовой аналогии: while — это «пока в холодильнике есть еда, продолжай есть», а for — это «съешь 5 конфет» или «перебери все буквы в слове». В обоих случаях вы повторяете действия, но во втором вам проще описать повторение без ручного управления счётчиком.

2. Синтаксис for: «для каждого … в …»

for читается почти как русская фраза: «для каждого элемента x из источника значений сделай тело». Общая форма такая: for (item in source) { ... }. Это не магия и не заклинание — это просто очень удобная запись, которая скрывает рутину: взять очередное значение, выполнить тело, перейти к следующему.

Важно сразу привыкнуть к мысли: переменная цикла (item, i, ch) — это «текущее значение», а не «переменная-счётчик, которую мы обязаны вручную увеличивать». В for увеличение шага делает сам цикл (за вас), и это одна из причин, почему код получается короче и спокойнее.

Простейший пример — пройти по списку слов (пока мы не изучаем коллекции глубоко, это просто демонстрация идеи):

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

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

3. Диапазоны a..b в for

Диапазон a..b — это способ сказать: «возьми все числа от a до b включительно». И вот здесь ключевое слово — включительно. Если вы пишете 1..5, то будут значения 1, 2, 3, 4 и 5 — всего пять шагов. Именно такой диапазон чаще всего используют, когда нужно повторить действие N раз или пройти «от и до».

В документации Kotlin for описывается как цикл, который умеет перебирать диапазоны (ranges) наряду с массивами и коллекциями. Это значит, что for (i in 1..10) — абсолютно «родной» стиль Kotlin, а не случайная фишка.

Мини-пример: «сделай 5 шагов»

Сделаем максимально прозрачный пример — просто напечатаем номер шага:

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

Здесь важно заметить две вещи.

Во‑первых, мы не пишем i = i + 1. Переменную i меняет цикл, а мы только используем текущий i.

Во‑вторых, переменная i внутри цикла ведёт себя как val: она создаётся заново для каждой итерации как «текущее значение». Если попытаться сделать i = i + 1, компилятор будет недоволен, и это, в общем-то, к лучшему: меньше способов сломать логику.

Табличка про «включительно»

Чтобы меньше наступать на грабли, полезно один раз зафиксировать:

Диапазон Значения внутри Сколько итераций
1..1
1
1
1..3
1, 2, 3
3
2..5
2, 3, 4, 5
4

Если вам нужно «ровно N повторов, начиная с 1», почти всегда подходит 1..N.

for как «повторить N раз» без ручного счётчика

В предыдущих лекциях с while мы делали классический «счётчик»: объявить var i = 1, проверить условие, внутри увеличить i. Это нормально и иногда необходимо. Но когда шаг очевидный и линейный (1, 2, 3…), for делает код компактнее и читабельнее: вы буквально видите границы прямо в заголовке цикла.

С практической точки зрения это означает: если задача звучит как «сделай 10 попыток», «прочитай 3 значения», «посчитай сумму от 1 до n», то for обычно будет вашим первым кандидатом. Он снижает риск бесконечного цикла, потому что вы не забываете увеличить счётчик — его просто нет.

Суммирование: сумма от 1 до n

Сумма чисел от 1 до n — это учебный пример не потому, что нам жизненно важно складывать числа (хотя бухгалтерия была бы не согласна), а потому что он тренирует сразу три навыка: переменная-накопитель, диапазон и аккуратная работа с границами.

Сделаем мини-программу: попросим n, если оно корректно и n >= 1 — посчитаем сумму через for.

fun main() {
    print("Введите 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("Некорректное n")
    }
}

Здесь есть маленькая хитрость читабельности: for (x in 1..n) sum += x можно писать в одну строку, потому что тело цикла — одна команда. Kotlin это позволяет. Но если у вас в цикле 2–3 действия, лучше ставить { }, чтобы не превращать программу в «поэму без переносов строк».

Как for (x in 1..n) «думает»

Иногда новичку проще понять цикл, если представить его как механизм, который повторяет шаги. Упрощённая логика диапазонного for выглядит так (не код Kotlin, а «как это работает по смыслу»):

flowchart TD
    A[Старт цикла] --> B[Взять следующее значение x из диапазона]
    B --> C{Есть значение?}
    C -- нет --> D[Выход из цикла]
    C -- да --> E[Выполнить тело цикла]
    E --> B

Это хорошо сочетается с идеей из документации Kotlin: for перебирает то, что даёт элементы через итератор, а диапазоны компилируются в оптимизированный перебор.

4. downTo и step: направление и шаг

В реальных задачах вам иногда нужно идти с конца (например, печатать последние значения первыми), иногда — брать элементы через один (например, обрабатывать только чётные позиции), иногда — и то и другое. Для этого Kotlin даёт две очень простые конструкции: downTo для обратного направления и step для величины шага.

Начнём с простого: обратный отсчёт.

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

При использовании downTo оба значения включаются в диапазон.

Теперь добавим шаг: «через 2».

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

Здесь удобно читать слева направо: «Начни с 10, иди вниз до 0, шаг 2».

5. Перебор строки в for

Теперь к самой «человеческой» части лекции: строка — это текст, а текст состоит из символов. Очень часто хочется пройтись по строке и что-то посчитать: сколько пробелов, сколько цифр, есть ли в тексте @, сколько раз встречается буква а (да, это уже почти мини-детектив).

В Kotlin строку можно перебирать в for напрямую: for (ch in text) { ... }. На каждой итерации ch будет иметь тип Char, то есть один символ. Даже если вы пока не проходили отдельную лекцию про Char, здесь достаточно понимать: это «одна буква/цифра/знак».

И важно: for по строке — это всё тот же принцип «перебираем источник значений», просто источником стала строка. В документации Kotlin подчёркивается, что for работает с любым объектом, у которого есть итератор. Строка как раз такой объект.

Вывести все символы по одному

fun main() {
    val word = "Kotlin"

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

Да, это выглядит как «я печатаю буквы по одной, чтобы почувствовать себя принтером 90‑х». Но практическая ценность в том, что теперь мы умеем делать проверки и подсчёты по каждому символу.

Подсчёты: пробелы и цифры

Сейчас мы сделаем маленький “Text Analyzer v0” (версия ноль-ноль-ноль-очень-ранняя): программа читает строку и считает, сколько в ней пробелов и сколько цифр. Мы не будем использовать никакие сложные штуки — только for, if и пару счётчиков.

Чтобы определить «цифра это или нет», можно сравнить символ с границами '0' и '9'. Символы можно сравнивать, потому что у них есть порядок (по кодам). Для новичка это звучит чуть странно, но на практике работает отлично для диапазонов цифр и латинских букв.

fun main() {
    print("Введите строку: ")
    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, цифр: $digits")
}

Если пользователь введёт Kotlin 2.3, вывод будет примерно таким:

// Введите строку: Kotlin 2.3
// Пробелов: 1, цифр: 2

Здесь мы постепенно подходим к полезной привычке: for часто идёт вместе с «счётчиками» (var), которые вы обновляете по условию.

6. Как выбрать: while, do-while или for

Сейчас будет важная мысль, которая спасает от «не того цикла». Технически многие задачи решаются разными циклами. Но хороший стиль — выбирать тот, который лучше выражает смысл.

while и do-while полезны, когда число повторов заранее неизвестно: «повторяй, пока ввод неверный» или «делай попытки, пока не угадаешь». А for — когда вы можете заранее описать источник шагов: диапазон чисел или последовательность символов. В документации Kotlin это формулируется прямо: for перебирает коллекции, массивы, диапазоны и вообще всё, что предоставляет итератор.

Табличка для быстрой ориентации:

Ситуация Обычно лучше читается
Повторять, пока условие истинно
while
Действие должно выполниться минимум один раз
do-while
Пройти по числам от a до b
for (i in a..b)
Пройти по всем символам строки
for (ch in text)

7. Типичные ошибки при работе с for

Ошибка №1: ожидать, что диапазон a..b “не включает b”.
Это, пожалуй, самая частая путаница после перехода с некоторых других языков и просто от невнимательности. В нашем курсе фиксируем жёстко: .. включает обе границы. Если вы хотите напечатать числа 1, 2, 3, 4, 5 — пишите 1..5, и всё будет честно.

Ошибка №2: пытаться вручную изменять переменную цикла внутри for.
В for переменная цикла — это «текущее значение», а не ваша личная игрушка. Если попытаться сделать i = i + 1, компилятор не даст. И это хорошо: так вы не сломаете шаг и не сделаете цикл непредсказуемым. Если вам нужно управлять шагом вручную — это уже кандидат на while (но сегодня мы просто запоминаем принцип).

Ошибка №3: использовать for для повторного ввода “пока не введут правильно”.
Иногда хочется написать «10 раз спросим ввод и вдруг повезёт». Но если пользователь вводит неверно, вы либо завершите попытки и получите некорректное состояние, либо будете усложнять логику. Для «повторяй до корректного значения» естественнее while или do-while, которые мы уже изучили.

Ошибка №4: смешивать разные смыслы в одной переменной-счётчике.
Например, когда вы одновременно считаете сумму, количество цифр и количество пробелов, легко случайно обновить «не тот» счётчик. Это не проблема for, это проблема читаемости. Спасает простое правило: одна переменная — один смысл. digits считает цифры, spaces — пробелы, sum — сумму, и не надо делать из x универсального солдата.

Ошибка №5: забывать про пустые строки и “ничего не происходит”.
Если пользователь ввёл пустую строку, for (ch in text) просто не выполнится ни разу — и это нормальное поведение (как и у while, когда условие сразу false). Главное — не паниковать: программа не сломалась, она честно не нашла ни одного символа для обработки.

1
Задача
Kotlin SELF, 4 уровень, 3 лекция
Недоступна
Этажи башни
Этажи башни
1
Задача
Kotlin SELF, 4 уровень, 3 лекция
Недоступна
Сумма маршрута
Сумма маршрута
1
Задача
Kotlin SELF, 4 уровень, 3 лекция
Недоступна
Нумерация символов
Нумерация символов
1
Задача
Kotlin SELF, 4 уровень, 3 лекция
Недоступна
Проверка строки
Проверка строки
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ