Swift 3 For Loop With Increment

How do a i+=2 for-loop in Swift?

Check this

for index in stride(from: 0, to: 5, by: 2){
print(index)
}

Multiple increments in Swift style for loops

Preconditions to answering this: looking over your example

I will assume that you intended to limit i by i < rawDataOut.count-3 rather than i < rawDataOut.count, otherwise the rawDataOut[i + 3] element access by index wouldn't make much sense w.r.t. runtime safety. Anyway, without you showing us rawDataOut, this is an assumption we shall have to make.

Hence, your original loop (including a verifiable example) looks as follows

/* example data */
var rawDataOut = Array(1...40)
var maskPixels = [Int](count: 10, repeatedValue: 0)

/* your pre-Swift 2.2/3.0 loop */
for var i: Int = 0, j: Int = 0; i < rawDataOut.count-3; i += 4, ++j {
maskPixels[j] = rawDataOut[i + 3]
}

print(maskPixels) //[4, 8, 12, 16, 20, 24, 28, 32, 36, 40]

Using for in ... where

In your specific example case, the multiple increments have a simple relation (j=4*i) so we could solve this without even making use of an explicit j iterate, e.g.

/* example data */
var rawDataOut = Array(1...40)
var maskPixels = [Int](count: 10, repeatedValue: 0)

/* your pre-Swift 2.2/3.0 loop */
for i in 0..<(rawDataOut.count-3) where i%4 == 0 {
maskPixels[i/4] = rawDataOut[i + 3]
}

print(maskPixels) // [4, 8, 12, 16, 20, 24, 28, 32, 36, 40]

but this is possibly not really of interest for the general discussion of two iterates. We move on to a 2-iterate method combining stride and enumerate.


Combining stride and enumerate

One solution is to enumerate the stride described by iterate i in your loop above, and use the enumeration index to construct the second iterate (j above). In your example, the enumerate index exactly corresponds to j, i.e.

/* example data */
var rawDataOut = Array(1...40)
var maskPixels = [Int](count: 10, repeatedValue: 0)

/* Swift >= 2.2 loop */
for (j, i) in 0.stride(to: rawDataOut.count-3, by: 4).enumerate() {
maskPixels[j] = rawDataOut[i + 3]
}

print(maskPixels) // [4, 8, 12, 16, 20, 24, 28, 32, 36, 40]

Note that in Swift 3 (as compared to 2.2), it seems as if the default implementations of stride(to:by:) and stride(through:by:) to protocol Strideable (as non-blueprinted extension methods) will be depracated, and that we're back to (as in Swift 1.2) using the global functions stride(from:to:by:) and stride(from:through:by:), see e.g. the current master branch of swift/stdlib/public/core/Stride.swift


Trickier cases: resort to while

For trickier cases, say a signature in your pre-Swift 2.2 loop as

for var i: Int = 0, j: Int = 0; i < rawDataOut.count-3; i += 4, j += i { ... }

you're probably best of simply using a while loop with one iterate associated with the loop invariant, and a trailing iterate as a free variable; whether this is considered messy or not is a matter of taste, I suppose.

var i = 0, j = 0
while i < rawDataOut.count-3 {

// ...

// increase iterates
i += 4
j += i
}

I assume the reason for removing the C-style loop is that it's, in most cases, directly covered by for in, stride etc, and for cases where these don't suffice, a good old' while, most likely, will.

How to create a for loop with a dynamic increment amount on each iteration in swift now that the C-style loop has been removed

Here's a corrected version using a regular for-in loop over the scaleIntervals. You also forgot about F# :-)

let scaleIntervals: [Int] = [2,2,1,2,2,2,1]
let notes: [String] = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]

func scale(fromNote tonicIndex: Int) -> [String] {
var result: [String] = []

var currentIndex = tonicIndex
for interval in scaleIntervals {
result.append(notes[currentIndex])
currentIndex = (currentIndex + interval) % notes.count
}

return result
}

print(scale(fromNote: 0)) // ["A", "B", "C#", "D", "E", "F#", "G#"]
print(scale(fromNote: 3)) // ["C", "D", "E", "F", "G", "A", "B"]

Just for fun, here's a single-expression version using reduce. This is really slow to typecheck and probably less efficient, but it's cute:

func scale(fromNote tonicIndex: Int) -> [String] {
return scaleIntervals.reduce((notes: [], index: 0), {
($0.notes + [notes[$0.index]], ($0.index + $1) % notes.count)
}).notes
}

Swift 3: replace c style for-loop with float increment

you can use stride function stride(through:, by:) for this .. something like

for hue in (minHue).stride(through: maxHue, by: hueIncrement){
// ...
}

From Swift3.0, you can use stride(from:to:by:) or stride(from:through:by:) syntax

for hue in stride(from: minHue, through: maxHue, by: hueIncrement){
//....
}

Swift 2.2 decrementing specific for loop in Swift 3

Your code isn't counting the number of 3-letter words in the array. It is counting the number of 3-letter words at the end of the array. It will return 0 for your sample input array.

When a C-style for loop is very complex, the final fallback solution is to translate it to a while loop. Any C-style for loop can be mechanically converted into an equivalent while loop, which means you can do it even if you don't fully understand what it is doing.

This for loop:

for initialization; condition; increment {
// body
}

is equivalent to:

initialization
while condition {
// body
increment
}

So, your code is equivalent to:

let array = ["hello", "world", nil, "foo", nil, "bar", "Peter Griffin"]
var threeLetterWords = 0

var i = array.count - 1
while i >= 0 && array[i]?.characters.count == 3 {
i -= 1
threeLetterWords += 1
}
print("Found words: \(threeLetterWords)") // says `Found words: 0`

Here is how to use a for loop and guard to do the equivalent of your code:

let array = ["hello", "world", nil, "foo", nil, "bar", "Peter Griffin"]
var num3LetterWords = 0

for word in array.reversed() {
guard word?.characters.count == 3 else { break }
num3LetterWords += 1
}

print(num3LetterWords)

Swift 3 - round-up double of for-loop

Credit to Martin R for this more Swift-y answer:

You can make use of the FloatingPoint protocol, whose behavior is detailed here, to always round up:
upperBound.rounded(.up)

Original Answer:

Based on this answer, using ceil(upperBound) will cause any value greater than (in your example) 12 to be rounded up to 13.

How can I do a Swift for-in loop with a step?

The Swift synonym for a "step" is "stride" - the Strideable protocol in fact, implemented by many common numerical types.

The equivalent of (i = 1; i < max; i+=2) is:

for i in stride(from: 1, to: max, by: 2) {
// Do something
}

Alternatively, to get the equivalent of i<=max, use the through variant:

for i in stride(from: 1, through: max, by: 2) {
// Do something
}

Note that stride returns a StrideTo/StrideThrough, which conforms to Sequence, so anything you can do with a sequence, you can do with the result of a call to stride (ie map, forEach, filter, etc). For example:

stride(from: 1, to: max, by: 2).forEach { i in
// Do something
}


Related Topics



Leave a reply



Submit