使用取模替代C风格循环

3

由于 C 风格的 for 语句已经被弃用,并将在 Swift 的未来版本中被移除,所以如何最好地实现以下内容:

for var i = startIndex; i != endIndex; i = (i + 1) % arrCount {
}

我想要遍历数组,但是想从中间某个位置开始,并一直遍历到我开始的位置。
编辑: startIndex > endIndex

startIndexendIndex 有什么关联? - Tim Vermeulen
你可以实现自己的 SequenceType 以进行模数迭代。 - Sulthan
@TimVermeulen 我已经添加了它们之间的关系。 - Witterquick
3个回答

2
"

while"应该是最好的选择:

var i = startIndex
while i != endIndex {
    i = (i + 1) % arrCount
}

1
您可以轻松地转移原始数组,参见以下示例:
let array = [3,4,5,6,7]
let startIndex = 3
let endIndex = 2

let head = array[0..<endIndex] // [3, 4]
let tail = array[startIndex..<array.count] // [6, 7]
let shiftedArray = tail + head // [6, 7, 3, 4]

for element in shiftedArray {
    // do something
}

1

这里提供一种解决方案,使用自定义的SequenceType和关联的GeneratorType,正如Sulthan在上面的评论中建议的那样。

优点是,这个序列非常易读且灵活。例如:

let startIndex = 3
let endIndex = 2
let array = [3, 4, 5, 6, 7]

ModuloSequence(start: startIndex, end: endIndex, divisor: array.count).map {
    array[$0]
}

从负面来看,实现起来相当冗长(至少我是这么认为的):

struct ModuloSequenceGenerator : GeneratorType {
    let end:Int, divisor:Int
    private var dividend:Int?

    init(start:Int, end:Int, divisor:Int) {
        self.dividend = start
        self.end = end
        self.divisor = divisor
    }

    mutating func next() -> Int? {
        guard let c = dividend where c != end else {
            return nil
        }
        dividend = (c + 1) % divisor
        return dividend
    }
}

struct ModuloSequence : SequenceType {
    let start:Int, end:Int, divisor:Int

    func generate() -> ModuloSequenceGenerator {
        return ModuloSequenceGenerator(start: start, end: end, divisor: divisor)
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接