Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to iterate for loop in reverse order in swift?

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 Ints!

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 range

Forward

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 index

Sometimes 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: numbers

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.

stride: elements of SequenceType

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 

Notes

  • @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