回答这个问题的先决条件:查看您的示例
我将假设您打算限制i
byi < rawDataOut.count-3
而不是i < rawDataOut.count
,否则rawDataOut[i + 3]
通过索引访问元素对运行时安全性没有多大意义。无论如何,如果没有您向我们展示rawDataOut
,这是我们必须做出的假设。
因此,您的原始循环(包括可验证的示例)如下所示
/* 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
在您的特定示例中,多个增量具有简单的关系 ( j=4*i
),因此我们甚至可以在不使用显式j
迭代的情况下解决此问题,例如
/* 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]
但这对于两个迭代的一般讨论可能并不真正感兴趣。我们继续使用结合stride
和的 2 次迭代方法enumerate
。
结合stride
和enumerate
一种解决方案是在上面的循环中枚举stride
由迭代描述的内容i
,并使用枚举索引来构造第二个迭代(j
上面)。在您的示例中,enumerate
索引完全对应于j
,即
/* 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]
请注意,在 Swift 3(与 2.2 相比)中,似乎stride(to:by:)
和stride(through:by:)
协议的默认实现Strideable
(作为非蓝图扩展方法)将被弃用,并且我们回到(如在 Swift 1.2 中)使用全局函数stride(from:to:by:)
和,参见例如swift/stdlib/public/core/Stride.swiftstride(from:through:by:)
的当前主分支
更棘手的案例:诉诸while
对于更棘手的情况,请在 Swift 2.2 之前的循环中说一个签名为
for var i: Int = 0, j: Int = 0; i < rawDataOut.count-3; i += 4, j += i { ... }
你可能最好简单地使用一个while
循环,其中一个迭代与循环不变量相关联,一个尾随迭代作为自由变量;我想这是否被认为是混乱的,是一个品味问题。
var i = 0, j = 0
while i < rawDataOut.count-3 {
// ...
// increase iterates
i += 4
j += i
}
我认为删除 C 样式循环的原因是,在大多数情况下,它直接由 等覆盖for in
,stride
而对于这些还不够的情况,while
很可能会使用旧的' 。