48

How do I write the following in Swift3?

for (f = first; f <= last; f += interval)          
{
    n += 1
}

This is my own attempt

for _ in 0.stride(to: last, by: interval)
{
    n += 1
}
4

5 回答 5

69

Swift 2.2 -> 3.0: Strideable:sstride(...)被全局stride(...)函数取代

在 Swift 2.2 中,我们可以(正如您自己尝试过的那样)使用蓝图(和默认实现)函数stride(through:by:)stride(to:by:) 协议Strideable

/* Swift 2.2: stride example usage */
let from = 0
let to = 10
let through = 10
let by = 1
for _ in from.stride(through, by: by) { } // from ... through (steps: 'by')
for _ in from.stride(to, by: by) { }      // from ..< to      (steps: 'by')

而在 Swift 3.0 中,这两个函数已被删除Strideable,取而代之的是全局函数stride(from:through:by:)stride(from:to:by:); 因此上述等效的 Swift 3.0 版本如下

/* Swift 3.0: stride example usage */
let from = 0
let to = 10
let through = 10
let by = 1
for _ in stride(from: from, through: through, by: by) { }
for _ in stride(from: from, to: to, by: by) { }

在您的示例中,您希望使用闭区间步幅替代stride(from:through:by:),因为循环中的不变量for使用与小于或等于( <=) 的比较。IE

/* example values of your parameters 'first', 'last' and 'interval' */
let first = 0
let last = 10
let interval = 2
var n = 0
for f in stride(from: first, through: last, by: interval) { 
    print(f)
    n += 1 
} // 0 2 4 6 8 10
print(n) // 6

当然,我们仅将您的循环用作从循环到for的通道的示例,您可以自然地,对于您的具体示例,只需计算而不需要循环()。forstridenn=1+(last-first)/interval

strideSwift 3.0:更复杂的迭代增量逻辑的替代方案

随着进化提案 SE-0094 的实施,Swift 3.0 引入了全局sequence函数:

stride对于具有更复杂的迭代增量关系的情况(本例中不是这种情况),这可能是一个合适的替代方案。

声明

func sequence<T>(first: T, next: @escaping (T) -> T?) -> 
         UnfoldSequence<T, (T?, Bool)>

func sequence<T, State>(state: State, 
                        next: @escaping (inout State) -> T?) ->
           UnfoldSequence<T, State>

我们将简要介绍这两个函数中的第一个。参数采用一个闭包,该next闭包应用一些逻辑来懒惰地构造给定当前元素的下一个序列元素(以 开头first)。next序列在返回时终止nil,如果 anext永不返回,则序列终止nil

应用于上面简单的恒定步幅示例,该sequence方法有点冗长和过度使用适合此目的的stride解决方案:

let first = 0
let last = 10
let interval = 2
var n = 0
for f in sequence(first: first,
                  next: { $0 + interval <= last ? $0 + interval : nil }) {
    print(f)
    n += 1
} // 0 2 4 6 8 10
print(n) // 6

然而,这些sequence函数对于具有非常量步幅的情况非常有用,例如在以下问答中涵盖的示例中:

只需注意以最终nil返回(如果不是:“无限”元素生成)来终止序列,或者,当 Swift 3.1 到来时,将其惰性生成与prefix(while:)序列方法结合使用,如进化提案SE-中所述0045 . 后者应用于此答案的运行示例使该sequence方法不那么冗长,显然包括元素生成的终止标准。

/* for Swift 3.1 */
// ... as above
for f in sequence(first: first, next: { $0 + interval })
    .prefix(while: { $0 <= last }) {
    print(f)
    n += 1
} // 0 2 4 6 8 10
print(n) // 6
于 2016-05-16T09:20:29.783 回答
37

使用 Swift 5,您可以选择以下 5 个示例之一来解决您的问题。


#1。使用stride(from:to:by:)功能

let first = 0
let last = 10
let interval = 2

let sequence = stride(from: first, to: last, by: interval)

for element in sequence {
    print(element)
}

/*
prints:
0
2
4
6
8
*/

#2。使用sequence(first:next:)功能

let first = 0
let last = 10
let interval = 2

let unfoldSequence = sequence(first: first, next: {
    $0 + interval < last ? $0 + interval : nil
})

for element in unfoldSequence {
    print(element)
}

/*
prints:
0
2
4
6
8
*/

#3。使用AnySequence init(_:)初始化器

let anySequence = AnySequence<Int>({ () -> AnyIterator<Int> in
    let first = 0
    let last = 10
    let interval = 2

    var value = first
    return AnyIterator<Int> {
        defer { value += interval }
        return value < last ? value : nil
    }
})

for element in anySequence {
    print(element)
}

/*
prints:
0
2
4
6
8
*/

#4。使用CountableRange filter(_:)方法

let first = 0
let last = 10
let interval = 2

let range = first ..< last
let lazyCollection = range.lazy.filter({ $0 % interval == 0 })

for element in lazyCollection {
    print(element)
}

/*
prints:
0
2
4
6
8
*/

#5。使用CountableRange flatMap(_:)方法

let first = 0
let last = 10
let interval = 2

let range = first ..< last
let lazyCollection = range.lazy.compactMap({ $0 % interval == 0 ? $0 : nil })

for element in lazyCollection {
    print(element)
}

/*
prints:
0
2
4
6
8
*/
于 2017-06-29T11:31:14.883 回答
15

简而言之,Swift 3.0 的工作代码:

let (first, last, interval) = (0, 100, 1)
var n = 0
for _ in stride(from: first, to: last, by: interval) {
    n += 1
}
于 2017-03-15T19:45:55.073 回答
0

我们也可以使用while循环作为替代方式

while first <= last {
    first += interval
}
于 2020-04-04T16:43:27.267 回答
-5

for _ in 0.stride(to: last, by: interval) { n += 1 }

于 2016-05-11T18:18:45.233 回答