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