cohen72
cohen72

Reputation: 2990

Swift 3.0 multiple conditions in c-style for loop

I understand how to write a for loop using swift syntax (using .enumerate() and .revers()), however how would I re-write (in swift) the following javascript version of for loop, considering I have multiple conditions to adhere to:

for(var j = 10; j >= 0 && array[j] > value; j--) {
    array[j + 1] = array[j];
}   

Upvotes: 0

Views: 692

Answers (3)

Hamish
Hamish

Reputation: 80901

For the sake of completion (I would personally prefer to use a for loop with a check for an early break, as others have already suggested) – in Swift 3.1 you could use Sequence's prefix(while:) method in order to get the suffix of the array's indices where the elements meet a given predicate.

var array = [2, 3, 6, 19, 20, 45, 100, 125, 7, 9, 21, 22]

let value = 6

for i in array.indices // the array's indices.
    .dropLast() // exclude the last index as we'll be accessing index + 1 in the loop.
    .reversed() // reversed so we can get the suffix that meets the predicate.
    .prefix(while: {array[$0] > value}) // the subsequence from the start of the 
{                                       // collection where elements meet the predicate.
    array[i + 1] = array[i]
}

print(array) // [2, 3, 6, 19, 19, 20, 45, 100, 125, 7, 9, 21]

This is assuming that you're looking to begin iterating at the penultimate index of the array. If you want to start at a particular index, you can say:

for i in (0...10).reversed().prefix(while: {array[$0] > value}) {
    array[i + 1] = array[i]
}

This will start at the index 10 and iterate down to 0, giving you the same behaviour to the code in your question.

It's worth noting that both of the above variants will first iterate through the reversed indices (until the predicate isn't met), and then through the array's elements. Although, in Swift 3.1, there is a version of prefix(while:) which operates on a lazy sequence – which would allow for just a single iteration through the elements until the predicate isn't met.

Until Swift 3.1, you can use the below extension to get prefix(while:) on a Collection:

extension Collection {
    func prefix(while predicate: (Self.Iterator.Element) throws -> Bool) rethrows -> Self.SubSequence {

        var index = startIndex

        while try index < endIndex && predicate(self[index]) {
            formIndex(after: &index)
        }
        return self[startIndex..<index]
    }
}

Upvotes: 0

vadian
vadian

Reputation: 285150

I'm not sure that produces exactly the same result, but this is one of the approaches in Swift 3

for j in stride(from:10, through:0, by: -1) {
   if array[j] <= value { break }
   array[j + 1] = array[j]
}

Upvotes: 2

Luca Angeletti
Luca Angeletti

Reputation: 59526

What about this?

for j in (0...10).reversed() {
    guard array[j] > value else { break }
    array[j + 1] = array[j]
}

Upvotes: 2

Related Questions