What is Swift Range Expressions?

Ashok Rawat
4 min readSep 26, 2022

--

Different Types Of Range Operators

A range is a series of values between two numeric intervals. Range instance can be created using the range operator. Swift includes several range operators, which are shortcuts for expressing a range of values. Range operators can include or exclude the upper range, start the range with some value or can end before some max value. Ranges in Swift allow us to select parts of Strings, collections, and other types.

The lowerBound of the range instance in Swift is used to get the lowest value or the starting point of a range and upperBound is used to get the highest value or the end point of a range.

ClosedRange

The ClosedRange operator (lower...upper) defines a range that runs from lower to upper, and includes the values lower and upper. The closed range operator operates contains both it’s lower bound and upper bound.

for n in 3...5 {
print(n)
}
// Prints "3"
// Prints "4"
// Prints "5"

ClosedRange instance can be created by using the closed range operator (...). The closed range operator’s initial value should be less than or equal to the upper value else it will throw a run time error. Therefore ClosedRange instance cannot represent an empty range.

let arrInstance: ClosedRange<Int> = 0...5
print(arrInstance.contains(3))
// true
let zeroInclusive = 0...0
zeroInclusive.contains(0)
// true
zeroInclusive.isEmpty
// false
let arrInstance1: ClosedRange<Int> = 4...3
//Fatal error: Range requires lowerBound <= upperBound

ClosedRange and CountableClosedRange is approximately the same but in case of CountableClosedRange the bound you are specifying should conform to Strideable protocol and bound.stride should conform to SignedInteger that mean CountableClosedRange can create with Int bounds only.

Even if we are iterate over a Double range in a for-in loop make use of stride(from:to:by:) or stride(from:through:by:) in which by: parameter defines what factor we want to increment in each iteration.

Half-Open Range

The Half-Open Range operator (lower..<upper) defines a range that runs from lower to upper, but it doesn’t include upper.

for n in 3..<5 {    
print(n)
}
// Prints "3"
// Prints "4"

Half-Open Range instance can be created by using the half-open range operator (lower..<upper). Half-Open Range instances can represent an empty interval, if both lower and upper values are same.

let arrInstance = 0..<5
print(arrInstance.contains(3))
// true
arrInstance.contains(6)
// false
let empty = 0..<0
empty.contains(0)
// false
empty.isEmpty
// true
// in collection for n in 3..<3 {
print(n)
}
// Nothing will print as lower and upper values are same
source

One Sided Range

One-Sided Range operator has a value on only one side and another side contains elements up to infinite that is why it is called One-sided range. We can create One-sided range using either of the ...upper , lower...or the ..<upper operator. Following are the different expressions for the One-sided range.

a) PartialRangeUpTo

PartialRangeUpTo instances are created by using the(..<upper). PartialRangeUpTo instance can be used to check if a value is contained in a particular range of values.

let partialRangeUpTo = ..<5
partialRangeUpTo.contains(4)
// true

You can use a PartialRangeUpTo instance of a collection’s indices to represent the range from the start of the collection up to, but not including, the partial range’s upper bound.

let numbers = [10, 20, 30, 40, 50, 60, 70]
print(numbers[..<3])
// Prints "[10, 20, 30]"

b) PartialRangeThrough

PartialRangeThrough instances are created by using the prefix closed range operator (...upper). PartialRangeThrough instance can be used to check if a value is contained in a particular range of values.

let partialRangeThrough = ...5
partialRangeThrough.contains(4)
// true

You can use a PartialRangeThrough instance of a collection’s indices to represent the range from the start of the collection up to, and including, the partial range’s upper bound.

let numbers = [10, 20, 30, 40, 50, 60, 70]
print(numbers[...3])
// Prints "[10, 20, 30, 40]"

c) PartialRangeFrom

PartialRangeFrom instances by using the postfix range operator (lower..). You can use a partial range to quickly check if a value is contained in a particular range of values

let partialRangeFrom = 5...
partialRangeFrom.contains(4)
// false
partialRangeFrom.contains(5)
// true

We can use a partial range of a collection’s indices to represent the range from the partial range’s lower bound up to the end of the collection.

let numbers = [10, 20, 30, 40, 50, 60, 70]
print(numbers[3...])
// Prints “[40, 50, 60, 70]”

PartialRangeFrom sequence counts upward indefinitely, so it is sugeested not use with methods that read the entire sequence before returning, such as map(_:), filter(_:), or suffix(_:). In other word, iterating over a PartialRangeFrom range requires to manually check where the loop should end otherwise it continue indefinitely and program can stuck.

All the above types of range operators can be used with loops if conditions, array iterations and even with switch case statements according to the use cases.

Things to remember

  • The lower bound value must be smaller or equal to the upper bound value.
  • The lower bound and upper bound values can be negative.
  • We can iterate over range (excluding one-sided range) using for-in loops.
  • We can use the range operator to access elements of an array and collections.

Thanks for reading, you can follow me on Medium for updated articles.

If you have any comments, questions, or recommendations feel free to post them in the comment section below! 👇 and please share and give claps 👏👏 if you liked this post.

--

--

Ashok Rawat

Mobile Engineer iOS | Swift | Objective-C | Python | React | Unity3D | Flutter