请考虑以下代码:
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循环的迭代(例如continueMany
或continue x
之类的东西)
答案 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?
谓词来构建自定义“跳过”序列
nil
:不要跳过下一次迭代,或.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
命名并没有真正解释其目的,可以重命名为具有更好语义的东西。