I have the following loop in my Swift code:
for var i:Int = 0, j:Int = 0; i < rawDataOut.count; i += 4, ++j {
maskPixels[j] = rawDataOut[i + 3]
}
I'm getting two warnings in Xcode:
I cannot see how to rewrite this in Swift's For In Loops to take into account the two variables and the 4-stride without it getting messy. Is there a simple elegant translation?
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]
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.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With