Диапазон (Range)
Диапазон представляет собой набор значений, который определяется начальной и конечной точкой. Диапазоны бывают полуоткрытые (Range) и закрытые (ClosedRange).
По типу данных относятся к структурам.
Полуоткрытый диапазон (Range) - полуоткрытый интервал от нижней границы до верхней границы, но не включая ее.
Закрытый диапазон (ClosedRange) - интервал от нижней границы до верхней границы включительно.
Экземпляр полуоткрытого диапазона создается с помощью оператора полуоткрытого диапазона (..<
):
let underFive = 0.0..<5.0
Экземпляр закрытого диапазона создается с помощью оператора полуоткрытого диапазона (...
):
let throughFive = 0...5
Границы диапазона могут иметь отрицательное значение:
// negative lower bound
let rangeOne = -3...1
// negative upper and lower bound
let rangeTwo = -9 ... -2
При этом следует разделять бинарный оператор диапазона (...
) от унарного минуса. В этом случае следует отделить пробелами с двух сторон бинарный оператор диапазона (...
).
Следует помнить, что нижняя граница диапазона не должна быть больше верхней границы. Это приведет к ошибке:
let throughFive = 3...1 // Fatal error: Range requires lowerBound <= upperBound
Если необходимо использовать диапазон в обратном порядке, следует использовать к нему метод reversed() (см. пример ниже).
Диапазоны имеют следующие свойства и методы:
- var isEmpty: Bool - логическое значение, указывающее, содержит ли диапазон элементы;
- let lowerBound: Bound - нижняя граница диапазона;
- let upperBound: Bound - верхняя граница диапазона;
- func contains(Bound) -> Bool - Возвращает логическое значение, указывающее, содержится ли данный элемент в пределах диапазона;
- func clamped(to: Range
) -> Range , - Возвращает копию этого диапазона, ограниченную заданным предельным диапазоном.
Использование диапазонов
Можно использовать экземпляр Range или ClosedRange, чтобы быстро проверить, содержится ли значение в определенном диапазоне значений. Следует помнить, что экземпляр Range не содержит верхнюю границу.
Пример:
underFive.contains(3.14)
// true
underFive.contains(6.28)
// false
underFive.contains(5.0)
// false
При этом экземпляр ClosedRange содержит как нижнюю, так и верхнюю границу.
Пример:
throughFive.contains(3)
// true
throughFive.contains(10)
// false
throughFive.contains(5)
// true
Поскольку закрытый диапазон включает верхнюю границу, это значение содержится в закрытом диапазоне, нижняя граница которого равна верхней границе. Поэтому экземпляр ClosedRange не может представлять пустой диапазон.
Пример:
let zeroInclusive = 0...0
zeroInclusive.contains(0)
// true
zeroInclusive.isEmpty
// false
Экземпляры Range могут представлять пустой интервал, в отличие от ClosedRange.
Пример:
let empty = 0.0..<0.0
empty.contains(0.0)
// false
empty.isEmpty
// true
Ограничение диапазона
Метод экземпляра clamped(to:) возвращает копию этого диапазона, ограниченную заданным предельным диапазоном.
- В качестве параметров передаются пределы - диапазон для ограничения границ этого диапазона.
- Возвращаемое значение - новый диапазон, зажатый в границах пределов.
Границы результата всегда ограничены границами пределов. Если два диапазона не перекрываются, результатом является одноэлементный диапазон на верхней или нижней границе пределов.
Пример Range (func clamped(to limits: Range<Bound>) -> Range<Bound>
):
let x: Range = 0..<20
print(x.clamped(to: 10..<1000))
// Prints "10..<20"
let y: Range = 0..<5
print(y.clamped(to: 10..<1000))
// Prints "10..<10"
Пример ClosedRange (func clamped(to limits: ClosedRange<Bound>) -> ClosedRange<Bound>
):
let x: ClosedRange = 0...20
print(x.clamped(to: 10...1000))
// Prints "10...20"
let y: ClosedRange = 0...5
print(y.clamped(to: 10...1000))
// Prints "10...10"
Использование диапазона как коллекции последовательных значений
Когда полуоткрытый диапазон (Range) или закрытый диапазон (ClosedRange) использует целые числа в качестве нижней и верхней границ или любой другой тип, который соответствует протоколу Strideable с целым шагом, можно использовать этот диапазон в цикле for-in или с любым методом последовательности (Sequence) или коллекции (Collection).
Использование диапазона в цикле
Элементы полуоткрытого диапазона — это последовательные значения от его нижней границы до верхней границы, но не включая ее.
Пример:
for n in 3..<5 {
print(n)
}
// Prints "3"
// Prints "4"
Элементы закрытого диапазона — это последовательные значения от нижней границы до верхней границы включительно.
Пример:
for n in 3...5 {
print(n)
}
// Prints "3"
// Prints "4"
// Prints "5"
Поскольку типы с плавающей запятой, такие как Float и Double, являются собственными типами Stride, их нельзя использовать в качестве границ счетного диапазона. Если вам нужно выполнить итерацию по последовательным значениям с плавающей запятой, см. функцию stride(from:to:by:).
Метод reversed()
Метод reversed() возвращает перевернутый наоборот диапазон:
let range = 5...8 // 5 6 7 8
for val in range.reversed() {
print(val)
}
// 8
// 7
// 6
// 5
Метод start(with:)
Метод start(with:) позволяет проверить, начинается ли диапазон с поддиапазона, который передается через параметр with:
let range = 5...8 // 5 6 7 8
let st1 = range.starts(with: 1...5) // false
let st2 = range.starts(with: 5...7) // true
Метод overlaps()
Метод overlaps() возвращает true, если два диапазона хотя бы частично совпадают:
let range = 5...8 // 5 6 7 8
range.overlaps(3...9) // true
range.overlaps(9...19) // false
Односторонний диапазон (One-sided Range)
Односторонний диапазон - это отдельный тип данных, который представляет собой диапазон с одной границей. Односторонний диапазон содержит элементы до бесконечности в одном направлении.
Например:
let range1 = ..<2
print(range1)
// PartialRangeUpTo<Int>(upperBound: 2)
let range2 = ...2
print(range2)
// PartialRangeThrough<Int>(upperBound: 2)
Здесь ...<2
— односторонний диапазон. Он содержит все элементы от 2 до -∞.
Точно так же диапазон 2...
:
let range3 = 2...
print(range3)
// PartialRangeFrom<Int>(lowerBound: 2)
содержит все элементы от 2 до +∞.
Можно проверить это, проверив, присутствует ли определенное число в диапазоне.
Например:
// one-sided range using
// ..< operator
let range1 = ..<2
// check if -9 is in the range
print(range1.contains(-1))
// true
// one-sided range using
// ... operator
let range2 = 2...
// check if 33 is in the range
print(range2.contains(33))
// true
В этом примере использовался метод contains(), чтобы проверить, присутствует ли определенное число в диапазоне.
Примечание. При одностороннем диапазоне - устанавливается только верхняя или нижняя граница.
Внимание. Так как односторонний диапазон с одной стороны содержит элементы до бесконечности, то не следует такой диапазон использовать, например цикле в качестве коллекции для перебора.
Еще полезные ссылки
Также информацию по диапазонам можно получить на странице официальной документации (Узнать больше про методы и свойства диапазонов).
Ссылки на официальную документацию: