Диапазоны и прогрессии
Kotlin позволяет легко создавать диапазоны значений с помощью функции rangeTo()
, которая находится в пакете kotlin.ranges
. У функции есть операторная форма - ..
. Обычно rangeTo()
используется совместно с функциями in
или !in
.
if (i in 1..4) { // эквивалентная запись 1 <= i && i <= 4
print(i)
}
У диапазонов целочисленных типов
(IntRange
,
LongRange
,
CharRange
)
есть дополнительная функция: они поддерживают итерацию. Эти диапазоны также являются прогрессиями.
Подобные диапазоны, как правило, используются в цикле for
.
fun main() {
for (i in 1..4) print(i) // 1234
}
Для перебора чисел в обратном порядке используйте функцию downTo
вместо ..
.
fun main() {
for (i in 4 downTo 1) print(i) // 4321
}
Можно перебирать числа с произвольным шагом. Осуществляется это с помощью функции step
.
fun main() {
for (i in 1..8 step 2) print(i) // 1357
println()
for (i in 8 downTo 1 step 2) print(i) // 8642
}
Если требуется перебрать диапазон чисел, исключая его последний элемент, то используйте функцию until
.
fun main() {
for (i in 1 until 10) { // i in [1, 10), 10 будет исключён
print(i) // 123456789
}
}
Диапазоны
В математическом смысле диапазон - это закрытый интервал: он определяется двумя значениями и они оба являются частью диапазона. Диапазоны применимы к сопоставимым (comparable) типам: имея порядок, вы можете определить, находится ли произвольный экземпляр в диапазоне между двумя заданными экземплярами.
Основная операция с диапазонами - это contains
, которая обычно используется в форме операторов in
и !in
.
Чтобы создать диапазон на основе ваших классов, вызовите функцию rangeTo()
для начального значения диапазона и укажите конечное значение в качестве аргумента. Чаще всего используется операторная форма функции rangeTo()
- ..
.
class Version(val major: Int, val minor: Int): Comparable<Version> {
override fun compareTo(other: Version): Int {
if (this.major != other.major) {
return this.major - other.major
}
return this.minor - other.minor
}
}
fun main() {
val versionRange = Version(1, 11)..Version(1, 30)
println(Version(0, 9) in versionRange) // false
println(Version(1, 20) in versionRange) // true
}
Прогрессии
Как показано в приведённых выше примерах, диапазоны целочисленных типов, таких как Int
, Long
и Char
, можно рассматривать как арифметические прогрессии.
В Kotlin есть специальные типы для определения таких прогрессий:
IntProgression
,
LongProgression
и
CharProgression
.
У прогрессий есть три основных свойства: first
, last
и step
, при этом step
не может быть нулём.
first
- это первый элемент. Последующие элементы - это предыдущий элемент плюс step
.
Итерация по прогрессии с положительным шагом (step
) эквивалентна индексируемому циклу for
в Java / JavaScript.
for (int i = first; i <= last; i += step) {
// ...
}
При неявном создании прогрессии путём итерации диапазона, элементы first
и last
этой прогрессии являются конечными точками диапазона, а step
равен 1.
fun main() {
for (i in 1..10) print(i) // 12345678910
}
Чтобы прогрессии задать собственный шаг, используйте функцию step
.
fun main() {
for (i in 1..8 step 2) print(i) // 1357
}
Последний элемент прогрессии (last
) рассчитывается следующим образом:
* Для положительного шага: максимальное значение, но не больше конечного значения - (last - first) % step == 0
.
* Для отрицательного шага: минимальное значение, но не меньше конечного значения - (last - first) % step == 0
.
Таким образом, элемент last
не всегда совпадает с конечным значением диапазона.
fun main() {
for (i in 1..9 step 3) print(i) // 147, last = 7
}
Чтобы создать прогрессию для итерации в обратном направлении, при определении диапазона используйте downTo
вместо ..
.
fun main() {
for (i in 4 downTo 1) print(i) // 4321
}
Прогрессии реализуют интерфейс Iterable<N>
, где N
- это Int
, Long
или Char
, поэтому вы можете использовать их в различных функциях коллекций, таких как map
, filter
и т. д.
fun main() {
println((1..10).filter { it % 2 == 0 }) // [2, 4, 6, 8, 10]
}