Xcode 6 beta 4 added two functions to iterate on ranges with a step other than one:
stride(from: to: by:)
, which is used with exclusive ranges and stride(from: through: by:)
, which is used with inclusive ranges.
To iterate on a range in reverse order, they can be used as below:
for index in stride(from: 5, to: 1, by: -1) {
print(index)
}
//prints 5, 4, 3, 2
for index in stride(from: 5, through: 1, by: -1) {
print(index)
}
//prints 5, 4, 3, 2, 1
Note that neither of those is a Range
member function. They are global functions that return either a StrideTo
or a StrideThrough
struct, which are defined differently from the Range
struct.
A previous version of this answer used the by()
member function of the Range
struct, which was removed in beta 4. If you want to see how that worked, check the edit history.
Apply the reverse function to the range to iterate backwards:
For Swift 1.2 and earlier:
// Print 10 through 1
for i in reverse(1...10) {
println(i)
}
It also works with half-open ranges:
// Print 9 through 1
for i in reverse(1..<10) {
println(i)
}
Note: reverse(1...10)
creates an array of type [Int]
, so while this might be fine for small ranges, it would be wise to use lazy
as shown below or consider the accepted stride
answer if your range is large.
To avoid creating a large array, use lazy
along with reverse()
. The following test runs efficiently in a Playground showing it is not creating an array with one trillion Int
s!
Test:
var count = 0
for i in lazy(1...1_000_000_000_000).reverse() {
if ++count > 5 {
break
}
println(i)
}
For Swift 2.0 in Xcode 7:
for i in (1...10).reverse() {
print(i)
}
Note that in Swift 2.0, (1...1_000_000_000_000).reverse()
is of type ReverseRandomAccessCollection<(Range<Int>)>
, so this works fine:
var count = 0
for i in (1...1_000_000_000_000).reverse() {
count += 1
if count > 5 {
break
}
print(i)
}
For Swift 3.0 reverse()
has been renamed to reversed()
:
for i in (1...10).reversed() {
print(i) // prints 10 through 1
}
Updated for Swift 3
The answer below is a summary of the available options. Choose the one that best fits your needs.
reversed
: numbers in a rangeForward
for index in 0..<5 {
print(index)
}
// 0
// 1
// 2
// 3
// 4
Backward
for index in (0..<5).reversed() {
print(index)
}
// 4
// 3
// 2
// 1
// 0
reversed
: elements in SequenceType
let animals = ["horse", "cow", "camel", "sheep", "goat"]
Forward
for animal in animals {
print(animal)
}
// horse
// cow
// camel
// sheep
// goat
Backward
for animal in animals.reversed() {
print(animal)
}
// goat
// sheep
// camel
// cow
// horse
reversed
: elements with an indexSometimes an index is needed when iterating through a collection. For that you can use enumerate()
, which returns a tuple. The first element of the tuple is the index and the second element is the object.
let animals = ["horse", "cow", "camel", "sheep", "goat"]
Forward
for (index, animal) in animals.enumerated() {
print("\(index), \(animal)")
}
// 0, horse
// 1, cow
// 2, camel
// 3, sheep
// 4, goat
Backward
for (index, animal) in animals.enumerated().reversed() {
print("\(index), \(animal)")
}
// 4, goat
// 3, sheep
// 2, camel
// 1, cow
// 0, horse
Note that as Ben Lachman noted in his answer, you probably want to do .enumerated().reversed()
rather than .reversed().enumerated()
(which would make the index numbers increase).
Stride is way to iterate without using a range. There are two forms. The comments at the end of the code show what the range version would be (assuming the increment size is 1).
startIndex.stride(to: endIndex, by: incrementSize) // startIndex..<endIndex
startIndex.stride(through: endIndex, by: incrementSize) // startIndex...endIndex
Forward
for index in stride(from: 0, to: 5, by: 1) {
print(index)
}
// 0
// 1
// 2
// 3
// 4
Backward
Changing the increment size to -1
allows you to go backward.
for index in stride(from: 4, through: 0, by: -1) {
print(index)
}
// 4
// 3
// 2
// 1
// 0
Note the to
and through
difference.
Forward by increments of 2
let animals = ["horse", "cow", "camel", "sheep", "goat"]
I'm using 2
in this example just to show another possibility.
for index in stride(from: 0, to: 5, by: 2) {
print("\(index), \(animals[index])")
}
// 0, horse
// 2, camel
// 4, goat
Backward
for index in stride(from: 4, through: 0, by: -1) {
print("\(index), \(animals[index])")
}
// 4, goat
// 3, sheep
// 2, camel
// 1, cow
// 0, horse
@matt has an interesting solution where he defines his own reverse operator and calls it >>>
. It doesn't take much code to define and is used like this:
for index in 5>>>0 {
print(index)
}
// 4
// 3
// 2
// 1
// 0
Check out On C-Style For Loops Removed from Swift 3
Swift 4 onwards
for i in stride(from: 5, to: 0, by: -1) {
print(i)
}
//prints 5, 4, 3, 2, 1
for i in stride(from: 5, through: 0, by: -1) {
print(i)
}
//prints 5, 4, 3, 2, 1, 0
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With