Swiftで逆範囲を操作する方法はありますか?
例えば:
for i in 5...1 {
// do something
}
無限ループです。
Swiftの新しいバージョンでは、コードはコンパイルされますが、実行時にエラーが発生します。
致命的エラー:upperBound <lowerBoundで範囲を形成できません
1..5代わりに、計算してインデックスとしてj = 6 - i使用できることを知っjています。もっと読みやすいものがあったのではないかと思っていました。
Swiftで逆範囲を操作する方法はありますか?
例えば:
for i in 5...1 {
// do something
}
無限ループです。
Swiftの新しいバージョンでは、コードはコンパイルされますが、実行時にエラーが発生します。
致命的エラー:upperBound <lowerBoundで範囲を形成できません
1..5代わりに、計算してインデックスとしてj = 6 - i使用できることを知っjています。もっと読みやすいものがあったのではないかと思っていました。
回答:
最新のSwift 3の更新(Swift 4でも動作します)
reversed()範囲でメソッドを使用できます
for i in (1...5).reversed() { print(i) } // 5 4 3 2 1
またはstride(from:through:by:)方法
for i in stride(from:5,through:1,by:-1) { print(i) } // 5 4 3 2 1
stide(from:to:by:) 似ていますが、最後の値を除外します
for i in stride(from:5,to:0,by:-1) { print(i) } // 5 4 3 2 1
最新のSwift 2の更新
まず、プロトコル拡張機能のreverse使用方法が変わります。
for i in (1...5).reverse() { print(i) } // 5 4 3 2 1
StrideはXcode 7 Beta 6で作り直されました。新しい使用法は次のとおりです。
for i in 0.stride(to: -8, by: -2) { print(i) } // 0 -2 -4 -6
for i in 0.stride(through: -8, by: -2) { print(i) } // 0 -2 -4 -6 -8
それはまた働きDoublesます:
for i in 0.5.stride(to:-0.1, by: -0.1) { print(i) }
ここで境界の浮動小数点比較を警戒してください。
Swift 1.2の以前の編集:Xcode 6 Beta 4以降では、byとReverseRangeはもう存在しません:[
範囲を反転するだけの場合は、reverse関数で十分です。
for i in reverse(1...5) { println(i) } // prints 5,4,3,2,1
0x7fffffffによって投稿されたように、任意の整数で反復および増分するために使用できる新しいストライド構成があります。Appleはまた、浮動小数点サポートが近づいていると述べた。
彼の答えから出典:
for x in stride(from: 0, through: -8, by: -2) {
println(x) // 0, -2, -4, -6, -8
}
for x in stride(from: 6, to: -2, by: -4) {
println(x) // 6, 2
}
(1...5).reverse()(関数呼び出しとして)する必要があります。答えを更新してください。(2文字しかないため、投稿を編集できませんでした。)
(1...5).reversed()。また、の例は.stride()機能せず、stride(from:to:by:)代わりにfree関数が必要です。
strideSwift 3 のコードは少し間違っているようです。番号1が含まれるように、あなたが使用する必要がありますthrough反対にto:このようなfor i in stride(from:5,through:1,by:-1) { print(i) }
reversed元のコレクションをラップするだけであり、それを構築するために反復を必要としないため、O(1)の複雑さがあることを指摘する価値があります。
これの非対称性について何か問題があります:
for i in (1..<5).reverse()
...これとは対照的に:
for i in 1..<5 {
つまり、リバースレンジを実行するたびに、かっこを忘れずに入力する必要があります。さらに.reverse()、最後にそれを書いて、親指のように突き出さなければなりません。これは、対称的なカウントアップとカウントダウンであるCスタイルのforループと比較すると、本当に醜いです。そのため、代わりにCスタイルのforループを使用する傾向がありました。しかし、Swift 2.2では、Cスタイルのforループは廃止されます。そのため、デクリメントしているすべてのCスタイルのforループをこの醜い.reverse()構造に置き換えることを急いでやらなければなりませんでした。ずっと疑問に思っているのに、なぜ地球上に逆範囲演算子がないのでしょうか。
ちょっと待って!これがSwiftです。独自の演算子を定義できます!! さあ行こう:
infix operator >>> {
associativity none
precedence 135
}
func >>> <Pos : ForwardIndexType where Pos : Comparable>(end:Pos, start:Pos)
-> ReverseRandomAccessCollection<(Range<Pos>)> {
return (start..<end).reverse()
}
だから今私は言うことが許されています:
for i in 5>>>1 {print(i)} // 4, 3, 2, 1
これは私のコードで発生する最も一般的なケースのみをカバーしていますが、最も一般的なケースは遠く離れているため、現在必要なのはこれだけです。
オペレーターの内部で一種の内部危機が発生しました。>..の逆なので、を使用したかったのですが..<、それは合法ではありません。ドット以外の後にドットを使用することはできません。私は考えました..>が、と区別するのが難しすぎると判断しました..<。いいところ>>>は、それがあなたに向かって叫ぶことです。(もちろん、あなたしている別のオペレータを思い付くために自由しかし、私のアドバイスは次のとおりです。超対称性のために、定義<<<何をし..<ていて、今、あなたは持っている<<<と>>>。入力しやすい左右対称とされています)
infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound) ->
ReversedRandomAccessCollection<CountableRange<Bound>>
where Bound : Comparable, Bound.Stride : Integer {
return (minimum..<maximum).reversed()
}
infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound)
-> ReversedRandomAccessCollection<CountableRange<Bound>>
where Bound : Comparable & Strideable {
return (minimum..<maximum).reversed()
}
infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound)
-> ReversedRandomAccessCollection<Range<Bound>>
where Bound : Strideable {
return (minimum..<maximum).reversed()
}
infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound)
-> ReversedCollection<Range<Bound>>
where Bound : Strideable {
return (minimum..<maximum).reversed()
}
>>>オペレーターは本当にかっこいい!reverse()かっこで囲まれた式の終わりに固執するのは変に感じるので、Swiftのデザイナーがそのようなことに注意を払うことを望みます。プロトコルは、ストライドが正か負かを判断するために使用できる完全に合理的な演算子を提供する5>..0ため、範囲を自動的に処理できなかった理由はありません。ForwardIndexTypedistanceTo()
この質問への回答は、ベータ版を進めるにつれて少し変わったようです。ベータ4以降、by()関数とReversedRange型の両方が言語から削除されました。逆の範囲を作成する場合は、次のオプションを使用できます。
1:前方範囲を作成し、reverse()関数を使用してそれを逆にします。
for x in reverse(0 ... 4) {
println(x) // 4, 3, 2, 1, 0
}
for x in reverse(0 ..< 4) {
println(x) // 3, 2, 1, 0
}
2:stride()ベータ4で追加された新しい関数を使用します。これには、開始インデックスと終了インデックス、および反復する量を指定する関数が含まれます。
for x in stride(from: 0, through: -8, by: -2) {
println(x) // 0, -2, -4, -6, -8
}
for x in stride(from: 6, to: -2, by: -4) {
println(x) // 6, 2
}
この投稿には、新しい排他的範囲演算子も含まれていることに注意してください。..に置き換えられました..<。
編集: Xcode 6 ベータ5リリースノートから、Appleはこれを処理するために次の提案を追加しました。
ReverseRangeは削除されました。lazy(x ..
ここに例があります。
for i in lazy(0...5).reverse() {
// 0, 1, 2, 3, 4, 5
}
lazy(0....5).reverse()ていますが、ベータ5リリースノートが表示されません。このトピックに関する他の議論を知っていますか?また、参考までに、forループ内の数値は、例では逆です。
// 0, 1, 2, 3, 4, 5いますが、実際には逆にする必要があります。コメントは誤解を招くものです。
Swift 3、4+:次のように実行できます:
for i in sequence(first: 10, next: {$0 - 1}) {
guard i >= 0 else {
break
}
print(i)
}
結果:10、9、8 ... 0
好きなようにカスタマイズできます。詳しくはリファレンスをご覧くださいfunc sequence<T>
Reverse()関数は逆数に使用されます。
Var n:Int //数値を入力
For i in 1 ... n.reverse(){Print(i)}