Kotlin цикл в цикле
Циклы представляют вид управляющих конструкций, которые позволяют в зависимости от определенных условий выполнять некоторое действие множество раз.
For
Цикл for пробегается по всем элементам коллекции. В этом плане цикл for в Kotlin эквивалентен циклу for-each в ряде других языков программирования. Его формальная форма выглядит следующим образом:
for(переменная in последовательность)
Например, выведем все квадраты чисел от 1 до 9, используя цикл for:
В данном случае перебирается последовательность чисел от 1 до 9. При каждом проходе цикла (итерации цикла) из этой последовательности будет извлекаться элемент и помещаться в переменную n. И через переменную n можно манипулировать значением элемента. То есть в данном случае мы получим следующий консольный вывод:
Циклы могут быть вложенными. Например, выведем таблицу умножения:
В итоге на консоль будет выведена следующая таблица умножения:
1 2 3 4 5 6 7 8 9 2 4 6 8 10 12 14 16 18 3 6 9 12 15 18 21 24 27 4 8 12 16 20 24 28 32 36 5 10 15 20 25 30 35 40 45 6 12 18 24 30 36 42 48 54 7 14 21 28 35 42 49 56 63 8 16 24 32 40 48 56 64 72 9 18 27 36 45 54 63 72 81
Цикл while
Цикл while повторяет определенные действия пока истинно некоторое условие:
Здесь пока переменная i больше 0, будет выполняться цикл, в котором на консоль будет выводиться квадрат значения i.
В данном случае вначале проверяется условие (i > 0) и если оно истинно (то есть возвращает true), то выполняется цикл. И вполне может быть ситуация, когда к началу выполнения цикла условие не будет выполняться. Например, переменная i изначально меньше 0, тогда цикл вообще не будет выполняться.
Но есть и другая форма цикла while — do..while:
В данном случае вначале выполняется блок кода после ключевого слова do , а потом оценивается условие после while. Если условие истинно, то повторяется выполнение блока после do. То есть несмотря на то, что в данном случае переменная i меньше 0 и она не соответствует условию, тем не менее блок do выполнится хотя бы один раз.
Операторы continue и break
Иногда при использовании цикла возникает необходимость при некоторых условиях не дожидаться выполнения всех инструкций в цикле, перейти к новой итерации. Для этого можно использовать оператор continue :
В данном случае когда n будет равно 5, сработает оператор continue. И последующая инструкция, которая выводит на консоль квадрат числа, не будет выполняться. Цикл перейдет к обработке следующего элемента в массиве
Бывает, что при некоторых условиях нам вовсе надо выйти из цикла, прекратить его выполнение. В этом случае применяется оператор break :
В данном случае когда n окажется равен 5, то с помощью оператора break будет выполнен выход из цикла. Цикл полностью завершится.
Циклы for, while, do-while, forEach, repeat()
Цикл for в Kotlin имеет другой синтаксис. В Java нам нужно инициализировать переменную перед началом цикла, затем указать условие и затем изменять переменную.
Это классический вариант, который применяется и в других языках. Но он довольно неудобный и не понятен для новичков. Например, часто путаются в использовании и .
В Kotlin упростили цикл. Для работы с циклом нужен итератор — массив, Map, интервал чисел и т.д.
Интервалы
Стандартный вариант, когда нужно пробежаться по заданному числу элементов, описывается следующим образом. Если для цикла используется одна команда, можно обойтись без фигурных скобок, но проще всегда использовать блок.
for(i in 1..5) println(i) // Лучше со скобками for(i in 1..5)
Оператор in и его брат !in проверяют вхождение или отсутствие вхождения в диапазон.
В выражении 1..5 мы указываем диапазон от 1 до 5 (пять входит в диапазон). Переменная последовательно примет значение
Диапазон можно заменить переменной.
val range = 1..5 for(i in range)
Списки и множества
fun main() < val list = listOf("C", "A", "T") for (letter in list) < print(letter) >// Можно явно указать тип for (str: String in setOf("C", "A", "T")) < print(str) >>
Map
val capitals = mapOf( "USA" to "Washington DC", "England" to "London", "France" to "Paris" ) for ((country, capital) in capitals)
Массивы
val cats = arrayListOf() cats.add("Мурзик") cats.add("Васька") cats.add("Барсик") for(cat in cats) < println("Кот $cat") >// Результат Кот Мурзик Кот Васька Кот Барсик
Этот же пример можно переписать, используя индекс:
Проверим, является ли символ не цифрой.
fun isNotDigit(c: Char) = c !in '0'..'9' println(isNotDigit('3')) // false, это всё-таки цифра
С помощью index, element и withIndex() можно получить индекс и его значение в массиве.
val cats = arrayListOf("Barsik", "Murzik", "Vaska") for( (index, element) in cats.withIndex())
0: Мурзик 1: Васька 2: Барсик
А как быть с вариантами, когда нужно счётчик не увеличивать на единицу, а уменьшать на 2? Используем ключевые слова downTo и step.
for(i in 10 downTo 1 step 2) < print("$i ") >// выводит: 10 8 6 4 2
Без указания шага значения будут уменьшаться на единицу.
for(i in 10 downTo 1) < print("$i ") >// 10 9 8 7 6 5 4 3 2 1 for (letter in 'Z' downTo 'A') print(letter) // ZYXWVUTSRQPONMLKJIHGFEDCBA
Очень часто в циклах встречается выражение size-1, чтобы не выйти за пределы массива. Можно заменить на until.
for(i in 0..cats.size - 1) < println(cats[i]) >for(i in 0 until cats.size)
Хотим выйти из цикла при достижении какого-то значения.
for (i in 1..5) < println(i) // прекращаем перебор, когда достигнем значения 3 if (i == 3) break >// Получим 1 2 3
Ключевое слово continue позволяет продолжить перебор, при этом можно что-то сделать во время перебора, например, мяукнуть. Число 5 при этом не выводится.
println("For loop 1 to 10 continue if number is 5") for (i in 1..10) < if (i == 5) < println("Meow") continue >println(i) > // Результат For loop 1 to 10 continue if number is 5 1 2 3 4 Meow 6 7 8 9 10
Вложенные циклы for
Часто используют два цикла for. Простейший вариант.
// первый цикл for(x in 1..3) < // второй вложенный цикл for(y in 1..3)< print("$x $y \n") >> // результат 1 1 1 2 1 3 2 1 2 2 2 3 3 1 3 2 3 3
Если мы хотим досрочно прервать на каком-то этапе цикл, то можем добавить аннотацию outerLoop@ к первому циклу и внутри второго цикла вызвать [email protected]. Как только значения станут равными (2 2), цикл завершится досрочно.
// первый цикл outerLoop@ for (x in 1..3) < // второй вложенный цикл for (y in 1..3) < print("$x $y \n") if (x == 2 && y == 2) brea[email protected] > > // результат 1 1 1 2 1 3 2 1 2 2
forEach
Пройтись по всем элементам коллекции.
val daysOfWeek = listOf("Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday") daysOfWeek.forEach
repeat()
Встроенная функция для повторения команд заданное число раз.
while
Цикл while работает стандартным способом — пока условие остаётся истинным, выполняются команды в блоке цикла. Если код после условия цикла состоит из одной строчки, то фигурные скобки можно опустить.
var i = 1 while (i < 9) < println(i) i = i + 1 >// вышли из цикла и проверяем последнее значение переменной println(i) // 9
Обратите внимание, что внутри цикла мы получим числа от 0 до 8, но если проверить, чему равно значение переменной после цикла, то увидим, что оно больше.
Прервать цикл можно через break.
var i = 1 while (i < 9) < if (i == 5)< break >println(i) i += 1 > // результат 1 2 3 4
do-while
Выполняем какую-то работу, пока выполняется какое-то условие — выводим число, которое увеличивается на единицу, пока число меньше 10.
Можно прервать цикл через break. Когда число станет равным 5, цикл прекратится.
Conditions and loops
In Kotlin, if is an expression: it returns a value. Therefore, there is no ternary operator ( condition ? then : else ) because ordinary if works fine in this role.
fun main() < val a = 2 val b = 3 //sampleStart var max = a if (a < b) max = b // With else if (a >b) < max = a >else < max = b >// As expression max = if (a > b) a else b // You can also use `else if` in expressions: val maxLimit = 1 val maxOrLimit = if (maxLimit > a) maxLimit else if (a > b) a else b //sampleEnd println(«max is $max») println(«maxOrLimit is $maxOrLimit») >
Branches of an if expression can be blocks. In this case, the last expression is the value of a block:
If you’re using if as an expression, for example, for returning its value or assigning it to a variable, the else branch is mandatory.
When expression
when defines a conditional expression with multiple branches. It is similar to the switch statement in C-like languages. Its simple form looks like this.
when matches its argument against all branches sequentially until some branch condition is satisfied.
when can be used either as an expression or as a statement. If it is used as an expression, the value of the first matching branch becomes the value of the overall expression. If it is used as a statement, the values of individual branches are ignored. Just like with if , each branch can be a block, and its value is the value of the last expression in the block.
The else branch is evaluated if none of the other branch conditions are satisfied.
If when is used as an expression, the else branch is mandatory, unless the compiler can prove that all possible cases are covered with branch conditions, for example, with enum class entries and sealed class subtypes).
enum class Bit < ZERO, ONE >val numericValue = when (getRandomBit()) < Bit.ZERO ->0 Bit.ONE -> 1 // ‘else’ is not required because all cases are covered >
In when statements, the else branch is mandatory in the following conditions:
- when has a subject of a Boolean , enum , or sealed type, or their nullable counterparts.
- branches of when don’t cover all possible cases for this subject.
enum class Color < RED, GREEN, BLUE >when (getColor()) < Color.RED ->println(«red») Color.GREEN -> println(«green») Color.BLUE -> println(«blue») // ‘else’ is not required because all cases are covered > when (getColor()) < Color.RED ->println(«red») // no branches for GREEN and BLUE else -> println(«not red») // ‘else’ is required >
To define a common behavior for multiple cases, combine their conditions in a single line with a comma:
You can use arbitrary expressions (not only constants) as branch conditions
You can also check a value for being in or !in a range or a collection:
when (x) < in 1..10 ->print(«x is in the range») in validNumbers -> print(«x is valid») !in 10..20 -> print(«x is outside the range») else -> print(«none of the above») >
Another option is checking that a value is or !is of a particular type. Note that, due to smart casts, you can access the methods and properties of the type without any extra checks.
when can also be used as a replacement for an if — else if chain. If no argument is supplied, the branch conditions are simply boolean expressions, and a branch is executed when its condition is true:
You can capture when subject in a variable using following syntax:
fun Request.getBody() = when (val response = executeRequest()) < is Success ->response.body is HttpError -> throw HttpException(response.status) >
The scope of variable introduced in when subject is restricted to the body of this when.
For loops
The for loop iterates through anything that provides an iterator. This is equivalent to the foreach loop in languages like C#. The syntax of for is the following:
The body of for can be a block.
As mentioned before, for iterates through anything that provides an iterator. This means that it:
- has a member or an extension function iterator() that returns Iterator<> :
- has a member or an extension function next()
- has a member or an extension function hasNext() that returns Boolean .
All of these three functions need to be marked as operator .
To iterate over a range of numbers, use a range expression:
A for loop over a range or an array is compiled to an index-based loop that does not create an iterator object.
If you want to iterate through an array or a list with an index, you can do it this way:
Alternatively, you can use the withIndex library function:
While loops
while and do-while loops execute their body continuously while their condition is satisfied. The difference between them is the condition checking time:
- while checks the condition and, if it’s satisfied, executes the body and then returns to the condition check.
- do-while executes the body and then checks the condition. If it’s satisfied, the loop repeats. So, the body of do-while executes at least once regardless of the condition.
Break and continue in loops
Kotlin supports traditional break and continue operators in loops. See Returns and jumps.