Swift3で次のように書くにはどうすればよいですか?
for (f = first; f <= last; f += interval)
{
n += 1
}
これは私自身の試みです
for _ in 0.stride(to: last, by: interval)
{
n += 1
}
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
を計算するだけです。
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
で始まる)を指定して次のシーケンス要素を遅延的に構築するためのロジックを適用するクロージャーを取ります。シーケンスは、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
関数は、ストライドが一定でない場合に非常に便利になります。次の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
Swift 5を使用すると、問題を解決するために、次の5つの例のいずれかを選択できます。
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
*/
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
*/
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
*/
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
*/
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
*/
単に、Swift 3.0の作業コード:
let (first, last, interval) = (0, 100, 1)
var n = 0
for _ in stride(from: first, to: last, by: interval) {
n += 1
}