Циклы в Kotlin
Цикл — разновидность управляющей конструкции в высокоуровневых языках программирования, предназначенная для организации многократного исполнения набора инструкций. (Wikipedia)
Простыми словами это просто конструкции которые нам помогают исполнять многократно какие то инструкции. Например: у нас есть массив в нем оценки студентов, допустим в массиве 1000 оценок, перебирать их вручную просто не реально поэтому мы используем цикл. Без цикла нам бы пришлось написать 1000 строчек кода проверяя например с помощью условия if что нам нужно, возможно мы ищем лучшую оценку и.т.д. С помощью циклов мы можем повторить одну и туже операцию 1000 раз просто меняя номер ячейки в массиве, в таком случае у нас будет всего несколько строчек когда а не 1000.
Для этих целей в Kotlin мы можем использовать цикл for, while и do while.
Давайте рассмотрим примеры использования цикла for. У цикла for есть разные конструкции для создания цикла, например:
val fruitArray = listOf("Яблоко", "Апельсин", "Груша") for(fruit in fruitArray){ //Начало цикла Log.d("MyLog", "Fruit: $fruit") // Конец цикла если цикл уже запустился // столько раз сколько элементов в массиве // если нет то запускается снова взяв // следующий элемент из массива } // fruit это один элемент массива который нам выдает цикл // цикл достает по очереди элементы из массива // и записывает их в переменную fruit // in проверяет берет элемент из массива и присваивает его переменной fruit // fruitArray это массив который содержит название фруктов }
Результат будет следующий, в консоли LogCat мы увидем выход:
- Fruit: Яблоко
- Fruit: Апельсин
- Fruit: Груша
В данном случае мы берем из массива с помощью цикла сразу элемент массива и мы незнаем на какой позиции данный элемент, но иногда нам нужно знать позицию элемента и нам нужен сам элемент с данной позиции, для этих случаев у массива есть диапазон элементов внутри. Для этого просто после названия массива пишем indices, данный метод нам возвращает диапазон. Например как в нашем примере fruitArray.indices выдаст диапазон 0..2, этот диапазон принимает цикл и в таком случае будет записывать в переменную fruit не элемент из массива а его позицию. По этому мы называем теперь эту переменную например index.
val fruitArray = listOf("Яблоко", "Апельсин", "Груша") Log.d("MyLog", "Range: ${fruitArray.indices}")
в данном примере fruitArray.indices без цикла нам просто выдает диапазон позиций, выход в LogCat будет следующий:
- Range: 0..2
Используя indices мы получаем позицию каждый раз когда запускается цикл и с помощью позиции мы можем получить элемент массива, надеюсь вы помните как можно получить элемент массива по позиции, таким образом у нас есть и позиция и сам элемент. Вот простой пример:
val fruitArray = listOf("Яблоко", "Апельсин", "Груша") for(index in fruitArray.indices){ //Начало цикла Log.d("MyLog", "Fruit: ${fruitArray[index]} | Fruit position: $index") // Конец цикла если цикл уже запустился // столько раз сколько элементов в массиве // если нет то запускается снова взяв // следующий элемент из массива } // index позиция которую нам выдает цикл // цикл запускает столько раз сколько элементов в массиве // меняя каждый раз index на новую позицию // используя index берем с этой позиции // из массива fruitArray, элемент по его позиции }
Выход в LogCat будет следующий:
- Fruit: Яблоко | Fruit position: 0
- Fruit: Апельсин | Fruit position: 1
- Fruit: Груша | Fruit position: 2
Для этих целей есть и специальная конструкция которая сразу выдаст две переменные позицию и элемент из массива на этой позиции, для этого используем метод который есть у массива withIndex() и так как у нас теперь будет две переменные, нам нужно заключить их в скобки и написать через запятую, пример: (index, item). В первую переменную запишется позиция а во вторую элемент из массива:
val fruitArray = listOf("Яблоко", "Апельсин", "Груша") for((index, fruit) in fruitArray.withIndex()){ Log.d("MyLog", "Fruit: $fruit | Index: $index ") }
Результат будет следующий:
- Fruit: Яблоко | Index: 0
- Fruit: Апельсин | Index: 1
- Fruit: Груша | Index: 2
Если мы хотим запустить цикл определенное количество раз не используя массив мы можем сами указать диапазон таким способом:
for(index in 0..10){ Log.d("MyLog", "Index: $index") }
Результат будет следующий:
- Index: 0
- Index: 1
- Index: 2
- Index: 3
- Index: 4
- Index: 5
- Index: 6
- Index: 7
- Index: 8
- Index: 9
- Index: 10
цикл запустился 11 раз
А что если нам нужно запустить цикл на оборот, что бы он запускал позиции от последней к первой? Для этого у нас тоже есть ключевые слова в цикле это downTo и step. Ключевое слово downTo указывает циклу что нужно запускать позиции от большей к меньшей и впереди ключевого слова downTo пишем до какой позиции. Например downTo 3 от последней до позиции 3. Посмотрим как это выглядит в коде и результат:
for(index in 10 downTo 3){ Log.d("MyLog", "Index: $index ") }
Результат будет следующий:
- Index: 10
- Index: 9
- Index: 8
- Index: 7
- Index: 6
- Index: 5
- Index: 4
- Index: 3
тоже самое можно сделать и с буквами:
for(letter in 'Z' downTo 'A'){ Log.d("MyLog", "Index: $letter ") }
Думаю вы догадались какой будет результат.
Иногда бывает так что нам нужно запустить цикл не от первой позиции а например с позиции 10 или с половины массива, в данном случае мы не можем использовать indices так как нам выдаст диапазон 0..9, в таких случаях мы можем использовать ключевое слово until. мы указываем начальную позицию ключевое слово until и после размер массива size. В таком случае нам не нужно беспокоится что мы выйдем за пределы массива.
Можно было бы и самим побеспокоится чтобы не выйти за пределы массива не используя ключевое слово until, использую диапазон и размер массива size – 1. Вот пример где выходим за пределы массива и выходит ошибка :
val fruitArray = listOf("Яблоко", "Апельсин", "Груша") for(index in 1..fruitArray.size){ Log.d("MyLog", "Fruit: ${fruitArray[index]} ") }
В данном примере я указал что цикл будет считать с позиции 1 а на этой позиции у нас “Апельсин” по этому когда цикл запустится то с помощью переменной index будет брать из массива элементы начиная с позиции 1 до размера массива, мы уже об этом говорили, у нас в массиве в данном случае 3 элемента это значит что размер массива это 3, вот тут и возникает проблема, цикл будет запускаться до позиции 3 включительно но у нас последняя позиция это позиция 2. Такой будет результат при запуске данного кода:
- Fruit: Апельсин
- Fruit: Груша
java.lang.ArrayIndexOutOfBoundsException: length=3; index=3
Мы вышли за пределы массива! Чтобы этого не произошло просто нужно добавить -1 к размеру массива тогда цикл будет запускать позиции как нужно и никогда не выйдет за пределы массива:
val fruitArray = listOf("Яблоко", "Апельсин", "Груша") for(index in 1..fruitArray.size - 1){ Log.d("MyLog", "Fruit: ${fruitArray[index]} ") }
Теперь все верно результат будет уже без ошибки:
- Fruit: Апельсин
- Fruit: Груша
Но Android Studio нас будет предупреждать что мы можем упростить данный код и убедится что цикл не выйдет за пределы массива с помощью ключевого слова until.
val fruitArray = listOf("Яблоко", "Апельсин", "Груша") for(index in 1 until fruitArray.size){ Log.d("MyLog", "Fruit: ${fruitArray[index]} ") }
Мы можем прервать цикл в любой момент используя ключевое слово break.
val fruitArray = listOf("Яблоко", "Апельсин", "Груша") for(fruit in fruitArray){ if(fruit == "Апельсин") break Log.d("MyLog", "Fruit: $fruit") } }
когда цикл дойдет до элемента “Апельсин” цикл прервется. Результат будет такой:
- Fruit: Яблоко
Мы можем “перепрыгнуть” одну позицию и продолжить цикл со следующей позиции с помощью continue:
val fruitArray = listOf("Яблоко", "Апельсин", "Груша") for(fruit in fruitArray){ if(fruit == "Апельсин") continue Log.d("MyLog", "Fruit: $fruit") } }
результат будет такой:
- Fruit: Яблоко
- Fruit: Груша
У массивов и списков есть и встроенный цикл forEach который пройдется по всем элементам массива или списка:
val fruitArray = listOf("Яблоко", "Апельсин", "Груша") fruitArray.forEach { Log.d("MyLog", "Fruit: $it") }
В данном случае этот цикл нам будет по очереди выдавать элементы массива в виде переменной it, результат будет такой:
- Fruit: Яблоко
- Fruit: Апельсин
- Fruit: Груша
В Kotlin есть еще цикл while и do while эти два цикла одинаковые разница лишь в том что do while один раз точно запустится а дальше уже зависит от условия которое напишем. Цикл while только запустится если условие верно.
Оба цикла принимают значение true или false поэтому мы можем использовать условия как в условии if. Вот пример обоих циклов:
val fruitArray = listOf("Яблоко", "Апельсин", "Груша") var index = 0 while (index < fruitArray.size){ Log.d("MyLog","Fruit: ${fruitArray[index]}") index++ }
Результат будет такой:
- Fruit: Яблоко
- Fruit: Апельсин
- Fruit: Груша
Но если мы сделаем например index = 5 то цикл просто не запуститься так как условие будет выдавать false а вот do while в таком случае один раз все равно запустится но выдаст ошибку так как мы пытаемся взять с позиции 5 элемент массива а такой позиции у нас нет. Так пишется цикл do while:
val fruitArray = listOf("Яблоко", "Апельсин", "Груша") var index = 0 do { Log.d("MyLog","Fruit: ${fruitArray[index]}") index++ } while (index < fruitArray.size)
В данном случае ошибок нет и работает как и while, результат будет такой же:
- Fruit: Яблоко
- Fruit: Апельсин
- Fruit: Груша
но в случае если index выбран больше чем размер массива один раз все равно запустится но выдаст ошибку о которой написано выше. Таким образом работают циклы, на практике будем на реальных примерах изучать как работают циклы и где их применять.
Здравствуйте!
Подскажите пожалуйста библиотеку для для рисования графиков функций для kotlin.
https://charts-kt.io/try-it/