Swiftで範囲を反転


105

Swiftで逆範囲を操作する方法はありますか?

例えば:

for i in 5...1 {
  // do something
}

無限ループです。

Swiftの新しいバージョンでは、コードはコンパイルされますが、実行時にエラーが発生します。

致命的エラー:upperBound <lowerBoundで範囲を形成できません

1..5代わりに、計算してインデックスとしてj = 6 - i使用できることを知っjています。もっと読みやすいものがあったのではないかと思っていました。


参照してください私の答えスウィフト3とあなたの問題を解決するために8通りにあきらめ同様の質問には
Imanouプチ

回答:


184

最新の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以降では、byReverseRangeはもう存在しません:[

範囲を反転するだけの場合は、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
}

FYIストライドはベータ6以降変更されました
DogCoffee 2015

1
(1...5).reverse()(関数呼び出しとして)する必要があります。答えを更新してください。(2文字しかないため、投稿を編集できませんでした。)
Behdad

Swift 3.0-PREVIEW-4(およびおそらく以前のバージョン)では、である必要があります(1...5).reversed()。また、の例は.stride()機能せず、stride(from:to:by:)代わりにfree関数が必要です。
davidA 2016

2
strideSwift 3 のコードは少し間違っているようです。番号1が含まれるように、あなたが使用する必要がありますthrough反対にto:このようなfor i in stride(from:5,through:1,by:-1) { print(i) }
262Hz

4
reversed元のコレクションをラップするだけであり、それを構築するために反復を必要としないため、O(1)の複雑さがあることを指摘する価値があります。
devios1 2018年

21

これの非対称性について何か問題があります:

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

これは私のコードで発生する最も一般的なケースのみをカバーしていますが、最も一般的なケース遠く離れているため、現在必要なのはこれだけです。

オペレーターの内部で一種の内部危機が発生しました。>..の逆なので、を使用したかったのですが..<、それは合法ではありません。ドット以外の後にドットを使用することはできません。私は考えました..>が、と区別するのが難しすぎると判断しました..<。いいところ>>>は、それがあなたに向かって叫ぶことです。(もちろん、あなたしている別のオペレータを思い付くために自由しかし、私のアドバイスは次のとおりです。超対称性のために、定義<<<何をし..<ていて、今、あなたは持っている<<<>>>。入力しやすい左右対称とされています)


Swift 3バージョン(Xcode 8シード6):

infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound) ->
    ReversedRandomAccessCollection<CountableRange<Bound>> 
    where Bound : Comparable, Bound.Stride : Integer {
        return (minimum..<maximum).reversed()
}

Swift 4バージョン(Xcode 9ベータ3):

infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound)
    -> ReversedRandomAccessCollection<CountableRange<Bound>>
    where Bound : Comparable & Strideable { 
        return (minimum..<maximum).reversed()
}

Swift 4.2バージョン(Xcode 10ベータ1):

infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound)
    -> ReversedRandomAccessCollection<Range<Bound>>
    where Bound : Strideable { 
        return (minimum..<maximum).reversed()
}

Swift 5バージョン(Xcode 10.2.1):

infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound)
    -> ReversedCollection<Range<Bound>>
    where Bound : Strideable {
        return (minimum..<maximum).reversed()
}

1
うわー、>>>オペレーターは本当にかっこいい!reverse()かっこで囲まれた式の終わりに固執するのは変に感じるので、Swiftのデザイナーがそのようなことに注意を払うことを望みます。プロトコルは、ストライドが正か負かを判断するために使用できる完全に合理的な演算子を提供する5>..0ため、範囲を自動的に処理できなかった理由はありません。ForwardIndexTypedistanceTo()
dasblinkenlight 2016年

1
@dasblinkenlightに感謝-これは私のアプリの1つに、Swift Cスタイルのforループに移行したC forループ(Objective-C)がたくさんあり、Cスタイルのforループのために変換する必要があったため、私に思いつきましたなくなります。これらのループは私のアプリのロジックのコアを表しており、すべてを書き直すと破損のリスクがあったため、これは単に恐ろしいことでした。したがって、私は(コメントアウトされた)Cスタイルの表記との対応を可能な限り明確にする表記を求めていました。
マット

きちんと!きれいに見えるコードへの執着が好きです!
ヨスト

10

この質問への回答は、ベータ版を進めるにつれて少し変わったようです。ベータ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
}

+1参照先を探しlazy(0....5).reverse()ていますが、ベータ5リリースノートが表示されません。このトピックに関する他の議論を知っていますか?また、参考までに、forループ内の数値は、例では逆です。
Rob

1
@Rob Hmmベータ版のリリースノートが最終的に削除されることを理解しておく必要がありました。私がこれを書いたとき、それは私がlazy()への参照を見た唯一の場所でした。これを指摘してくれてありがとう。
Mick MacCallum 2014年

1
@ 0x7fffffff最後の例では、コメントは言って// 0, 1, 2, 3, 4, 5いますが、実際には逆にする必要があります。コメントは誤解を招くものです。
パンジュン

5

Xcode 7、ベータ2:

for i in (1...5).reverse() {
  // do something
}

3

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>


1

これは、これを行う別の方法である可能性があります。

(1...5).reversed().forEach { print($0) }

-2

Reverse()関数は逆数に使用されます。

Var n:Int //数値を入力

For i in 1 ... n.reverse(){Print(i)}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.