How to iterate for loop in reverse order in swift?
Asked Answered
D

16

241

When I use the for loop in Playground, everything worked fine, until I changed the first parameter of for loop to be the highest value. (iterated in descending order)

Is this a bug? Did any one else have it?

for index in 510..509
{
    var a = 10
}

The counter that displays the number of iterations that will be executions keeps ticking...

enter image description here

Diamonddiamondback answered 1/7, 2014 at 10:59 Comment(4)
possible duplicate of Reverse Range in SwiftMisinform
Such a brilliant decision to drop c style loops. Bring them backEcumenicist
See my answer with Swift 5 that shows up to 4 different ways to iterate in reverse order.Acaroid
simply .reversed(), as in for index in (509 ... 510).reversed() { ... }Orson
L
302

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.

Lissalissak answered 1/7, 2014 at 12:17 Comment(3)
With Swift 2.0 it is now: 5.stride(to: 1, by: -1) or 5.stride(through: 1, by: -1)Wherever
With Swift 3.0 we're back to stride as a free function.Lissalissak
@Shaun it is a reasonable and safe choice. I can't tell you often R programmers are tripped by its : operator implicitly iterating downwards, causing their loops to execute when they thought it would skip over them. It's very convenient for interactive use, but terribly error prone in scripts, to the point where style guides recommend against using it.Jewfish
H
234

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
}
Halibut answered 22/7, 2014 at 11:52 Comment(1)
reversed may copy the collection, though. At least, that's how I understand the documentation on Data.Noah
P
133

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

Passport answered 11/6, 2016 at 4:3 Comment(0)
E
53

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
Etherege answered 26/10, 2015 at 5:57 Comment(0)
A
49

With Swift 5, according to your needs, you may choose one of the four following Playground code examples in order to solve your problem.


#1. Using ClosedRange reversed() method

ClosedRange has a method called reversed(). reversed() method has the following declaration:

func reversed() -> ReversedCollection<ClosedRange<Bound>>

Returns a view presenting the elements of the collection in reverse order.

Usage:

let reversedCollection = (0 ... 5).reversed()

for index in reversedCollection {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

As an alternative, you can use Range reversed() method:

let reversedCollection = (0 ..< 6).reversed()

for index in reversedCollection {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

#2. Using sequence(first:next:) function

Swift Standard Library provides a function called sequence(first:next:). sequence(first:next:) has the following declaration:

func sequence<T>(first: T, next: @escaping (T) -> T?) -> UnfoldFirstSequence<T>

Returns a sequence formed from first and repeated lazy applications of next.

Usage:

let unfoldSequence = sequence(first: 5, next: {
    $0 > 0 ? $0 - 1 : nil
})

for index in unfoldSequence {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

#3. Using stride(from:through:by:) function

Swift Standard Library provides a function called stride(from:through:by:). stride(from:through:by:) has the following declaration:

func stride<T>(from start: T, through end: T, by stride: T.Stride) -> StrideThrough<T> where T : Strideable

Returns a sequence from a starting value toward, and possibly including, an end value, stepping by the specified amount.

Usage:

let sequence = stride(from: 5, through: 0, by: -1)

for index in sequence {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

As an alternative, you can use stride(from:to:by:):

let sequence = stride(from: 5, to: -1, by: -1)

for index in sequence {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

#4. Using AnyIterator init(_:) initializer

AnyIterator has an initializer called init(_:). init(_:) has the following declaration:

init(_ body: @escaping () -> AnyIterator<Element>.Element?)

Creates an iterator that wraps the given closure in its next() method.

Usage:

var index = 5

guard index >= 0 else { fatalError("index must be positive or equal to zero") }

let iterator = AnyIterator({ () -> Int? in
    defer { index = index - 1 }
    return index >= 0 ? index : nil
})

for index in iterator {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

If needed, you can refactor the previous code by creating an extension method for Int and wrapping your iterator in it:

extension Int {

    func iterateDownTo(_ endIndex: Int) -> AnyIterator<Int> {
        var index = self
        guard index >= endIndex else { fatalError("self must be greater than or equal to endIndex") }

        let iterator = AnyIterator { () -> Int? in
            defer { index = index - 1 }
            return index >= endIndex ? index : nil
        }
        return iterator
    }

}

let iterator = 5.iterateDownTo(0)

for index in iterator {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/
Acaroid answered 26/2, 2017 at 11:8 Comment(1)
sequence(first: 5, next: { ($0 > 0) ? ($0 - 1) : nil }) // is simpler than ($0 - 1 >= 0)Genoese
K
29

For Swift 2.0 and above you should apply reverse on a range collection

for i in (0 ..< 10).reverse() {
  // process
}

It has been renamed to .reversed() in Swift 3.0

Kinsella answered 22/3, 2016 at 13:10 Comment(0)
E
9

In Swift 4 and latter

    let count = 50//For example
    for i in (1...count).reversed() {
        print(i)
    }
Elegit answered 26/3, 2018 at 6:21 Comment(0)
C
6

Swift 4.0

for i in stride(from: 5, to: 0, by: -1) {
    print(i) // 5,4,3,2,1
}

If you want to include the to value:

for i in stride(from: 5, through: 0, by: -1) {
    print(i) // 5,4,3,2,1,0
}
Coloration answered 29/9, 2017 at 9:38 Comment(0)
F
3

If one is wanting to iterate through an array (Array or more generally any SequenceType) in reverse. You have a few additional options.

First you can reverse() the array and loop through it as normal. However I prefer to use enumerate() much of the time since it outputs a tuple containing the object and it's index.

The one thing to note here is that it is important to call these in the right order:

for (index, element) in array.enumerate().reverse()

yields indexes in descending order (which is what I generally expect). whereas:

for (index, element) in array.reverse().enumerate() (which is a closer match to NSArray's reverseEnumerator)

walks the array backward but outputs ascending indexes.

Farhi answered 2/6, 2016 at 7:3 Comment(0)
A
3

as for Swift 2.2 , Xcode 7.3 (10,June,2016) :

for (index,number) in (0...10).enumerate() {
    print("index \(index) , number \(number)")
}

for (index,number) in (0...10).reverse().enumerate() {
    print("index \(index) , number \(number)")
}

Output :

index 0 , number 0
index 1 , number 1
index 2 , number 2
index 3 , number 3
index 4 , number 4
index 5 , number 5
index 6 , number 6
index 7 , number 7
index 8 , number 8
index 9 , number 9
index 10 , number 10


index 0 , number 10
index 1 , number 9
index 2 , number 8
index 3 , number 7
index 4 , number 6
index 5 , number 5
index 6 , number 4
index 7 , number 3
index 8 , number 2
index 9 , number 1
index 10 , number 0
Ablebodied answered 10/6, 2016 at 3:46 Comment(0)
B
2

You can consider using the C-Style while loop instead. This works just fine in Swift 3:

var i = 5 
while i > 0 { 
    print(i)
    i -= 1
}
Brier answered 7/5, 2017 at 13:12 Comment(0)
E
2

This will works decrement by one in reverse order.

let num1 = [1,2,3,4,5]
for item in nums1.enumerated().reversed() { 

    print(item.offset) // Print the index number: 4,3,2,1,0
    print(item.element) // Print the value :5,4,3,2,1

}

Or you can use this index, value property

let num1 = [1,2,3,4,5]
for (index,item) in nums1.enumerated().reversed() { 

    print(index) // Print the index number: 4,3,2,1,0
    print(item) // Print the value :5,4,3,2,1

}
Enochenol answered 13/3, 2022 at 10:3 Comment(0)
A
1
var sum1 = 0
for i in 0...100{
    sum1 += i
}
print (sum1)

for i in (10...100).reverse(){
    sum1 /= i
}
print(sum1)
Abukir answered 21/7, 2016 at 5:19 Comment(0)
A
1

You can use reversed() method for easily reverse values.

var i:Int
for i in 1..10.reversed() {
    print(i)
}

The reversed() method reverse the values.

Aguirre answered 19/6, 2018 at 6:4 Comment(0)
O
1

Reversing an array can be done with just single step .reverse()

var arrOfnum = [1,2,3,4,5,6]
arrOfnum.reverse()
Overblouse answered 17/1, 2022 at 8:38 Comment(0)
D
-3

For me, this is the best way.

var arrayOfNums = [1,4,5,68,9,10]

for i in 0..<arrayOfNums.count {
    print(arrayOfNums[arrayOfNums.count - i - 1])
}
Dirt answered 26/8, 2020 at 21:23 Comment(1)
The best native wayNutty

© 2022 - 2024 — McMap. All rights reserved.