Swift Ranges
Ranges express a span of values between a lower and upper bound and power everything from loops to array slicing.
Closed Ranges with ...
The closed range operator (a...b) produces a range that runs from a to b inclusive, meaning both endpoints are included in the sequence. It requires that a be less than or equal to b, otherwise Swift raises a runtime error. Closed ranges are the natural choice whenever the upper bound itself is a value you want to include, such as looping from 1 to 10.
Looping with a closed range
for day in 1...7 {
print("Day \(day) of the week")
}
// Prints Day 1 ... Day 7, seven lines totalHalf-Open Ranges with ..<
The half-open range operator (a..<b) runs from a up to, but not including, b. This is especially useful when working with array indices, since a collection's valid indices run from 0 up to (but excluding) its count — writing 0..<array.count avoids ever indexing one past the end.
Half-open range over an array's indices
let colors = ["red", "green", "blue"]
for index in 0..<colors.count {
print("\(index): \(colors[index])")
}
// 0: red
// 1: green
// 2: blueOne-Sided Ranges
Swift also supports one-sided ranges, where you omit one end of the range and let Swift infer it from context. array[2...] means from index 2 to the end, while array[..<2] means everything before index 2. One-sided ranges cannot be iterated directly with for-in because they have no defined starting or ending point on their own, but they work perfectly for subscripting collections.
Slicing an array with one-sided ranges
let letters = ["a", "b", "c", "d", "e"]
let fromThird = letters[2...] // ["c", "d", "e"]
let firstTwo = letters[..<2] // ["a", "b"]
print(fromThird)
print(firstTwo)Ranges as Values
Ranges are not just loop syntax — they are first-class values of type ClosedRange<Int> or Range<Int> (or generic over any Comparable type). You can store a range in a constant, pass it to a function, and query it with contains(_:), which is handy for validating whether a number falls within acceptable bounds.
- 1...5 is a ClosedRange<Int> including both 1 and 5
- 1..<5 is a Range<Int> including 1 but excluding 5
- contains(_:) checks membership without looping manually
- Ranges work over any Comparable type, including Character and Double
- reversed() lets you iterate a range from high to low
Storing and querying a range
let validAges = 18...65
func checkEligibility(age: Int) -> String {
return validAges.contains(age) ? "Eligible" : "Not eligible"
}
print(checkEligibility(age: 30)) // Eligible
print(checkEligibility(age: 12)) // Not eligible
for n in (1...5).reversed() {
print(n) // 5, 4, 3, 2, 1
}Exercise: Swift Ranges
Which values are included in the range `1...5`?