带有增量的 Swift 3 for 循环
Posted
技术标签:
【中文标题】带有增量的 Swift 3 for 循环【英文标题】:Swift 3 for loop with increment 【发布时间】:2016-09-07 07:14:03 【问题描述】:如何在 Swift3 中编写以下代码?
for (f = first; f <= last; f += interval)
n += 1
这是我自己的尝试
for _ in 0.stride(to: last, by: interval)
n += 1
【问题讨论】:
【参考方案1】:for _ in 0.stride(to: last, by: interval) n += 1
【讨论】:
你不能在 Swift 3 中说0.stride
。【参考方案2】:
Swift 2.2 -> 3.0: Strideable
:s stride(...)
替换为全局 stride(...)
函数
在 Swift 2.2 中,我们可以(正如您自己尝试过的那样)利用蓝图(和默认实现)函数 stride(through:by:)
和 stride(to:by:)
from the protocol 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
中删除,取而代之的是 the global functions stride(from:through:by:)
and 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
循环中的不变量使用与小于 或等于 (<=
) 的比较。即
/* 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
循环作为从 for
循环到 stride
的段落的示例,您可以自然地,对于您的具体示例,只需计算 n
而无需一个循环 (n=1+(last-first)/interval
)。
Swift 3.0:stride
的替代方案,用于更复杂的迭代递增逻辑
随着the implementation of evolution proposal SE-0094,Swift 3.0 引入了全局sequence
函数:
sequence(first:next:)
,
sequence(state:next:)
,
对于具有更复杂的迭代增量关系的情况(本例中不是这种情况),它可以是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
时序列终止,如果next
永远不会返回nil
,则序列终止。
应用于上面简单的常量步幅示例,sequence
方法有点冗长和过度杀伤 w.r.t。适合此用途的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
【讨论】:
我们不是在 Swift 2 中远离全局函数,而在 Swift 3 中回归它们吗? > 新版本的 swift 中的 stride 是什么?【参考方案3】:Swift 3.0 的简单工作代码:
let (first, last, interval) = (0, 100, 1)
var n = 0
for _ in stride(from: first, to: last, by: interval)
n += 1
【讨论】:
如果你正在遍历一个数组并且也想要一个索引,你可以使用enumerated()
,如下所示:***.com/a/24028458/8047【参考方案4】:
使用 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
*/
【讨论】:
【参考方案5】:我们也可以使用while
循环作为替代方式
while first <= last
first += interval
【讨论】:
以上是关于带有增量的 Swift 3 for 循环的主要内容,如果未能解决你的问题,请参考以下文章