3
for i in 0...10 {
  println("\(i)")
}

...will count from 0 to 10. What's the best way to count from 10 to 0?

rob
  • 4,069
  • 3
  • 34
  • 41
  • Just wanted to point out that it seems kind of dumb that Swift cannot handle the case of: for i in 10...0 { println("\(i)") } It seems like Swift should be able to figure out that the second index is smaller than the first index and then decrement instead of increment the stride – Adam Freeman Nov 10 '15 at 18:02

2 Answers2

5

You can use reverse to reverse a range (or any collection):

for i in reverse(0...10) {
    println("\(i)")
}

Or if you want more control, you can use stride, new in beta 4:

for i in stride(from: 10, through: 0, by: -1) { // includes 0
    println("\(i)")
}

for i in stride(from: 10, to: 0, by: -1) { // doesn't include 0
    println("\(i)")
}

DANGER ZONE

if you're feeling crafty, you can define your own custom syntax:

/*** NOT RECOMMENDED - confusing code! ***/

operator infix .. { precedence 136 /* 1 higher than ... and ..< */ }

@infix func ..<T: Strideable>(from: T, by: T.Stride) -> (start: T, stride: T.Stride) {
    return (start: from, stride: by)
}
@infix func ..<<T: Strideable>(fromBy: (start: T, stride: T.Stride), to: T) -> StrideTo<T> {
    return stride(from: fromBy.start, to: to, by: fromBy.stride)
}
@infix func ...<T: Strideable>(fromBy: (start: T, stride: T.Stride), through: T) -> StrideThrough<T> {
    return stride(from: fromBy.start, through: through, by: fromBy.stride)
}

Array(0..2..<10) // [0, 2, 4, 6, 8]
Array(0..2...10) // [0, 2, 4, 6, 8, 10]

Array(5..(-1)...0) // [5, 4, 3, 2, 1, 0]
Array(5..(-1)..<0) // [5, 4, 3, 2, 1]
Community
  • 1
  • 1
jtbandes
  • 115,675
  • 35
  • 233
  • 266
  • I think reverse reads nicely, but long-term I think stride will be the idiomatic way to do it since it's flexible and you can support it in user types by adopting a protocol – Jiaaro Jul 23 '14 at 20:32
  • @Jiaaro True; I also wouldn't be too surprised if `Range` were to be extended to types other than `ForwardIndex`. – jtbandes Jul 23 '14 at 20:50
  • Generally being crafty will produce a high WTF/min ration for other developers, not a good thing. We got operator overloading with Swift, best not to over use it—almost never. Will you understand this next year when you come across it: `Array(5..(-1)..<0)`? – zaph Jul 23 '14 at 21:29
  • @Zaph That's true. I'll add a comment above the code — I feel compelled to leave it here, however, to give people a taste of the kinds of things Swift can do. – jtbandes Jul 23 '14 at 21:34
  • This was a big problem with C++, now we have a new language and feel compelled to do it again. Swift makes me sad in so many ways knowing the mis-deeds that will be done, the un-readable code. One should ask oneself: What would [Uncle "Bob"](http://en.wikipedia.org/wiki/Robert_Cecil_Martin) say? – zaph Jul 23 '14 at 21:36
  • It's a dangerous balance between improved readability and hindered comprehension. Certain (most) things would *not* benefit from custom operators. A handful of things, IMO including strided ranges, would. The best outcome will be that such a stride operator is added to the language — though I bet this won't happen as long as there are no mixfix operators. (MATLAB and Python both have similar slice syntax using two `:`s.) – jtbandes Jul 23 '14 at 21:39
1

EDIT: C-style for loops will not be allowed in Swift 3 don't do it this way.

You can do it the traditional way:

for var i = 10; i >= 0; i-- {
  println("\(i)")
}

EDIT: I removed code using ReverseRange() because it was removed in Beta4

rob
  • 4,069
  • 3
  • 34
  • 41
  • thanks! I edited my answer to remove the ReverseRange code. – rob Jul 23 '14 at 20:44
  • 1
    FWIW these C-style `for` loops will be removed in Swift 3.0 https://github.com/apple/swift-evolution/blob/master/proposals/0007-remove-c-style-for-loops.md – pkamb Dec 23 '15 at 02:44