web-dev-qa-db-ja.com

Swift 3 for for loop with increment

Swift3で次のように書くにはどうすればよいですか?

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

これは私自身の試みです

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

Swift 2.2-> 3.0:Strideable:s stride(...)はグローバルな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では、これら2つの関数は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) { }

あなたの例では、forループの不変式がlessまたはequal<=)との比較を使用するため、クローズドインターバルストライドの代替stride(from:through:by:)を使用します。つまり.

/* 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=1+(last-first)/interval)を使用せずにnを計算するだけです。

Swift 3.0:より複雑な反復インクリメントロジックのためのstrideの代替

進化提案SE-0094の実装 で、Swift 3.0はグローバルなsequence関数を導入しました:

これは、より複雑な反復インクリメント関係を持つケースのstrideの適切な代替となります(この例ではそうではありません)。

宣言(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>

これら2つの機能の最初の機能について簡単に説明します。 next引数は、現在の要素(firstで始まる)を指定して次のシーケンス要素を遅延的に構築するためのロジックを適用するクロージャーを取ります。シーケンスは、nextnilを返すとき、またはnextnilを返さない場合は無限に終了します。

上記の単純な定数ストライドの例に適用すると、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関数は、ストライドが一定でない場合に非常に便利になります。次のQ&Aで説明されている例のように:

最終的な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
63
dfri

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。 AnySequenceinit(_:)初期化子の使用

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。 CountableRangefilter(_:)メソッドの使用

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。 CountableRangeflatMap(_:)メソッドの使用

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
*/
26
Imanou Petit

単に、Swift 3.0の作業コード:

let (first, last, interval) = (0, 100, 1)
var n = 0
for _ in stride(from: first, to: last, by: interval) {
    n += 1
}
12
Dan Rosenstark