Is there a way to work with reverse ranges in Swift?
For example:
for i in 5...1 {
// do something
}
is an infinite loop.
It appears that the answers to this question have changed a bit as we've progressed through the betas. As of beta 4, both the by()
function and the ReversedRange
type have been removed from the language. If you're looking to make a reversed range, your options are now as follows:
1: Create a forward range, and then use the reverse()
function to reverse it.
for x in reverse(0 ... 4) {
println(x) // 4, 3, 2, 1, 0
}
for x in reverse(0 ..< 4) {
println(x) // 3, 2, 1, 0
}
2: Use the new stride()
functions that were added in beta 4, which includes functions to specify the starting and ending indexes, as well as the amount to iterate by.
for x in stride(from: 0, through: -8, by: -2) {
println(x) // 0, -2, -4, -6, -8
}
for x in stride(from: 6, to: -2, by: -4) {
println(x) // 6, 2
}
Note that I've also included the new exclusive range operator in this post as well. ..
was replaced with ..<
.
Edit: From the Xcode 6 beta 5 release notes, Apple added the following suggestion for handling this:
ReverseRange has been removed; use lazy(x..
Here's an example.
for i in lazy(0...5).reverse() {
// 0, 1, 2, 3, 4, 5
}
Reverse() function is used for reverse number.
Var n:Int // Enter number
For i in 1...n.reverse() { Print(i) }
Swift 3, 4+: you can do it like this:
for i in sequence(first: 10, next: {$0 - 1}) {
guard i >= 0 else {
break
}
print(i)
}
result: 10, 9, 8 ... 0
You can customise it any way you like. For more info read func sequence<T> reference
This could be another way of doing this.
(1...5).reversed().forEach { print($0) }
There's something troubling about the asymmetry of this:
for i in (1..<5).reverse()
...as opposed to this:
for i in 1..<5 {
It means that every time I want to do a reverse range, I have to remember to put the parentheses, plus I have to write that .reverse()
on the end, sticking out like a sore thumb. This is really ugly in comparison to C-style for loops, which are symmetrical counting up and counting down. So I tended to use C-style for loops instead. But in Swift 2.2, C-style for loops are going away! So I've had to scurry around replacing all my decrementing C-style for loops with this ugly .reverse()
construct — wondering all the while, why on earth isn't there a reverse-range operator?
But wait! This is Swift — we're allowed to define our own operators!! Here we go:
infix operator >>> {
associativity none
precedence 135
}
func >>> <Pos : ForwardIndexType where Pos : Comparable>(end:Pos, start:Pos)
-> ReverseRandomAccessCollection<(Range<Pos>)> {
return (start..<end).reverse()
}
So now I'm allowed to say:
for i in 5>>>1 {print(i)} // 4, 3, 2, 1
This covers just the most common case that occurs in my code, but it is far and away the most common case, so it's all I need at present.
I had a kind of internal crisis coming up with the operator. I would have liked to use >..
, as being the reverse of ..<
, but that's not legal: you can't use a dot after a non-dot, it appears. I considered ..>
but decided it was too hard to distinguish from ..<
. The nice thing about >>>
is that it screams at you: "down to!" (Of course you're free to come up with another operator. But my advice is: for super symmetry, define <<<
to do what ..<
does, and now you've got <<<
and >>>
which are symmetrical and easy to type.)
infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound) ->
ReversedRandomAccessCollection<CountableRange<Bound>>
where Bound : Comparable, Bound.Stride : Integer {
return (minimum..<maximum).reversed()
}
infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound)
-> ReversedRandomAccessCollection<CountableRange<Bound>>
where Bound : Comparable & Strideable {
return (minimum..<maximum).reversed()
}
infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound)
-> ReversedRandomAccessCollection<Range<Bound>>
where Bound : Strideable {
return (minimum..<maximum).reversed()
}
infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound)
-> ReversedCollection<Range<Bound>>
where Bound : Strideable {
return (minimum..<maximum).reversed()
}
Update For latest Swift 3 (still works in Swift 4)
You can use the reversed()
method on a range
for i in (1...5).reversed() { print(i) } // 5 4 3 2 1
Or stride(from:through:by:)
method
for i in stride(from:5,through:1,by:-1) { print(i) } // 5 4 3 2 1
stide(from:to:by:)
is similar but excludes the last value
for i in stride(from:5,to:0,by:-1) { print(i) } // 5 4 3 2 1
Update For latest Swift 2
First of all, protocol extensions change how reverse
is used:
for i in (1...5).reverse() { print(i) } // 5 4 3 2 1
Stride has been reworked in Xcode 7 Beta 6. The new usage is:
for i in 0.stride(to: -8, by: -2) { print(i) } // 0 -2 -4 -6
for i in 0.stride(through: -8, by: -2) { print(i) } // 0 -2 -4 -6 -8
It also works for Doubles
:
for i in 0.5.stride(to:-0.1, by: -0.1) { print(i) }
Be wary of floating point compares here for the bounds.
Earlier edit for Swift 1.2: As of Xcode 6 Beta 4, by and ReverseRange don't exist anymore :[
If you are just looking to reverse a range, the reverse function is all you need:
for i in reverse(1...5) { println(i) } // prints 5,4,3,2,1
As posted by 0x7fffffff there is a new stride construct which can be used to iterate and increment by arbitrary integers. Apple also stated that floating point support is coming.
Sourced from his answer:
for x in stride(from: 0, through: -8, by: -2) {
println(x) // 0, -2, -4, -6, -8
}
for x in stride(from: 6, to: -2, by: -4) {
println(x) // 6, 2
}