Swift 3 for 循环增量 [英] Swift 3 for loop with increment

查看:18
本文介绍了Swift 3 for 循环增量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我如何在 Swift3 中编写以下内容?

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

这是我自己的尝试

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

解决方案

Swift 2.2 -> 3.0: Strideable:s stride(...) 替换为 global <代码>stride(...) 函数

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

<块引用>

/* Swift 2.2: stride 示例用法 */让从 = 0让 = 10让通过 = 10让 = 1for _ in from.stride(through, by: by) { }//from ... through (steps: 'by')for _ in from.stride(to, by: by) { }//from ..<到(步骤:'by')

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

<块引用>

/* Swift 3.0: stride 示例用法 */让从 = 0让 = 10让通过 = 10让 = 1for _ in stride(from: from, through: through, by: by) { }for _ in stride(from: from, to: to, by: by) { }

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

/* 参数 'first'、'last' 和 'interval' 的示例值 */先让 = 0让最后= 10让间隔 = 2无功n = 0for f in stride(from: first, through: last, by: interval) {打印(f)n += 1}//0 2 4 6 8 10打印(n)//6

当然,我们使用您的 for 循环仅作为从 for 循环到 stride 的一段示例,因为您很自然地可以,对于您的具体示例,只需计算 n 而无需循环 (n=1+(last-first)/interval).

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

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

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

<块引用>

声明

func sequence(first: T, next: @escaping (T) -> T?) ->展开序列<T,(T?,Bool)>func sequence(state: State,下一个:@escaping (inout State) ->T?)->展开序列<T,状态>

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

应用于上面简单的常量步幅示例,sequence 方法有点冗长和矫枉过正.适合此目的的 stride 解决方案:

让第一个 = 0让最后= 10让间隔 = 2无功n = 0对于 f 顺序(第一:第一,下一个:{ $0 + 间隔 <= 最后一个?$0 + 间隔:nil }) {打印(f)n += 1}//0 2 4 6 8 10打印(n)//6

sequence 函数对于非恒定步幅的情况非常有用,但是,例如如以下问答中的示例所示:

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

/* 用于 Swift 3.1 *///... 如上for f in sequence(first: first, next: { $0 + interval }).prefix(while: { $0 <= last }) {打印(f)n += 1}//0 2 4 6 8 10打印(n)//6

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
}

解决方案

Swift 2.2 -> 3.0: Strideable:s stride(...) replaced by global stride(...) functions

In Swift 2.2, we can (as you've tried in your own attempt) make use of the blueprinted (and default-implemented) functions stride(through:by:) and 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')

Whereas in Swift 3.0, these two functions has been removed from Strideable in favour of the global functions stride(from:through:by:) and stride(from:to:by:); hence the equivalent Swift 3.0 version of the above follows as

/* 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) { }

In your example you want to use the closed interval stride alternative stride(from:through:by:), since the invariant in your for loop uses comparison to less or equal to (<=). I.e.

/* 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

Where, naturally, we use your for loop only as an example of the passage from for loop to stride, as you can naturally, for your specific example, just compute n without the need of a loop (n=1+(last-first)/interval).

Swift 3.0: An alternative to stride for more complex iterate increment logic

With the implementation of evolution proposal SE-0094, Swift 3.0 introduced the global sequence functions:

which can be an appropriate alternative to stride for cases with a more complex iterate increment relation (which is not the case in this example).

Declaration(s)

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>

We'll briefly look at the first of these two functions. The next arguments takes a closure that applies some logic to lazily construct next sequence element given the current one (starting with first). The sequence is terminated when next returns nil, or infinite, if a next never returns nil.

Applied to the simple constant-stride example above, the sequence method is a bit verbose and overkill w.r.t. the fit-for-this-purpose stride solution:

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

The sequence functions become very useful for cases with non-constant stride, however, e.g. as in the example covered in the following Q&A:

Just take care to terminate the sequence with an eventual nil return (if not: "infinite" element generation), or, when Swift 3.1 arrives, make use of its lazy generation in combination with the prefix(while:) method for sequences, as described in evolution proposal SE-0045. The latter applied to the running example of this answer makes the sequence approach less verbose, clearly including the termination criteria of the element generation.

/* 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 3 for 循环增量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆