你能告诉一个for循环有条件地超过一步吗?

时间:2018-03-10 16:55:17

标签: swift for-loop swift4 continue

请考虑以下代码:

let value = "ABCDE"

for letter in value {
    print(letter)
}

打印:

A
B
C
D
E

现在考虑一下假设的代码,当它找到' 2时,它会在循环中向前跳过2。这里的伪代码显示了我要问的内容......

let value = "AB2DE"

for letter in value {

    if letter == "2" {
        continue 2 <-- Does Swift support something similar to this?
    }

    print(letter)
}

以上将使输出看起来像这样:

A
B
E

注意:当然我可以通过管理跳过计数器,然后使用continue轻松实现这一点,在我去的时候递减计数器,或者,如果源支持下标,就像其他人建议的那样可以使用while循环来管理我自己的索引。有许多方法可以解决这个假设问题,但这不是我的问题的意图。

我的问题是专门找出该语言本身是否支持一次跳过一个for循环的迭代(例如continueManycontinue x之类的东西)

4 个答案:

答案 0 :(得分:4)

不,你无法改变for-in循环在循环中的迭代方式。

在这种情况下,带有自己的索引计数器的while循环可能是最简单的解决方案。虽然您可以在sequence(first:next:)循环中使用for-in

答案 1 :(得分:1)

您必须使用while循环。由于字符串索引推进在Swift中的工作方式,与许多其他语言相比,这有点复杂:

let value = "AB2DE"

var index: String.Index? = value.startIndex
while let charIndex = index, charIndex < value.endIndex {
    let letter = value[charIndex]

    if let digit = Int(String(letter)) {
        index = value.index(charIndex, offsetBy: digit, limitedBy: value.endIndex)
    } else {
        index = value.index(after: charIndex)
        print(letter)
    }
}

答案 2 :(得分:1)

问题中最后一段的答案是 - Swift没有类似continue N的声明。

但是,您可以使用其他一些语言结构来实现类似的结果。如果要跳过的元素是使用reduce来携带数字,则使用其中之一:

_ = value.reduce(0) { skip, char in
    // skip while we need to
    guard skip <= 0 else { return skip - 1 }
    // attempt to get a new skip count
    let skip = Int(String(char)) ?? 0
    if skip <= 0 {
        // do the actual work
        print(char)
    }
    // decrement the skip count
    return skip - 1
}

或者,更为迫切的方法是使用Iterator方法扩展skip,并使用迭代器遍历集合(集合上的for循环只是遍历迭代器的糖语法:

extension IteratorProtocol {
    @discardableResult
    mutating func skip(_ n: Int) -> Element? {
        guard n > 0 else { return next() }
        return skip(n-1)
    }
}

var it = value.makeIterator()
while let char = it.next() {
    if let n = Int(String(char)) {
        it.skip(n)
    } else {
        print(char)
    }
}

答案 3 :(得分:0)

您可以使用提供的Element -> Int?谓词来构建自定义“跳过”序列

  • if nil:不要跳过下一次迭代,或
  • if .some(number):跳过下一个number次迭代

然后使用此构造迭代您的序列(value)并有条件地向前跳。

E.g:

struct SkippingSequence<T: Sequence>: IteratorProtocol, Sequence {
    var iterator: T.Iterator
    let skipPredicate: (T.Element) -> Int?
    // skipPredicate:
    // - nil means no skip,
    // - .some(number) means to skip next 'number' of iterations.
    init(_ collection: T, _ skipPredicate: @escaping (T.Element) -> Int?) {
        self.iterator = collection.makeIterator()
        self.skipPredicate = skipPredicate
    }

    mutating func next() -> T.Element? {
        var n = iterator.next()
        if let skipNumIterations = n.flatMap({ skipPredicate($0) }) {
            for _ in 0..<skipNumIterations { n = iterator.next() }
        }
        return n
    }
}

申请你的例子:

let collection = "AB2DEF3HIJK"
for letter in SkippingSequence(collection, { Int(String($0)) }) {
    print(letter)
} /* A
     B
     E (skipped 2, D)
     F
     J (skipped 3, H, I)
     K */

skipPredicate命名并没有真正解释其目的,可以重命名为具有更好语义的东西。