forループを逆順で迅速に反復する方法は?


186

Playgroundでforループを使用すると、forループの最初のパラメーターを最高値に変更するまで、すべてが正常に機能しました。(降順で反復)

これはバグですか?他に誰か持っていましたか?

for index in 510..509
{
    var a = 10
}

実行される反復の数を表示するカウンターは、刻々と過ぎます...

ここに画像の説明を入力してください



1
cスタイルのループを削除するという素晴らしい決断。それらを戻す
Joel Teply

Swift 5での私の回答をご覧ください。逆の順序で反復する最大4つの異なる方法が示されています。
Imanou Petit

回答:


229

:Xcodeの6ベータ4は、1つの以外のステップと範囲に反復するために2つの機能を追加し stride(from: to: by:)、排他的な範囲で使用されるとstride(from: through: by:)、包括的範囲と共に使用されます。

逆の順序で範囲を反復処理するには、以下のように使用できます。

for index in stride(from: 5, to: 1, by: -1) {
    print(index)
}
//prints 5, 4, 3, 2

for index in stride(from: 5, through: 1, by: -1) {
    print(index)
}
//prints 5, 4, 3, 2, 1

これらはどちらもRangeメンバー関数ではないことに注意してください。これらは、a StrideToまたはStrideThroughstruct を返すグローバル関数であり、structとは定義が異なりRangeます。

この回答の以前のバージョンは、ベータ4で削除されby()Range構造体のメンバー関数を使用していました。それがどのように機能したかを確認したい場合は、編集履歴を確認してください。


26
Swift 2.0の場合は次のようになります。5.stride(to: 1, by: -1)または5.stride(through: 1, by: -1)
Binarian 2015

6
Swift 3.0では、フリー関数としてストライドに戻りました。
Cezar

@Shaunそれは合理的で安全な選択です。多くの場合、Rプログラマーが:暗黙的に下方向に反復する演算子によってつまずかれ、ループをスキップすると思ったときにループを実行させることがよくあるとは言えません。インタラクティブな使用には非常に便利ですが、スクリプトでエラーが発生しやすく、スタイルガイドが推奨するほどのエラーになります。
Davor Cubranic

212

逆関数を範囲に適用して、逆方向に反復します。

スウィフト1.2およびそれ以前:

// Print 10 through 1
for i in reverse(1...10) {
    println(i)
}

ハーフオープン範囲でも機能します。

// Print 9 through 1
for i in reverse(1..<10) {
    println(i)
}

注: reverse(1...10)はタイプの配列を作成する[Int]ため、範囲が小さい場合はこれで問題ないかもしれませんが、lazy以下に示すように使用するstrideか、範囲が大きい場合は受け入れられる回答を検討することをお勧めします。


大きな配列の作成を回避するには、lazyと一緒に使用しreverse()ます。次のテストはPlaygroundで効率的に実行され、1兆Int秒の配列を作成していないことを示しています。

テスト:

var count = 0
for i in lazy(1...1_000_000_000_000).reverse() {
    if ++count > 5 {
        break
    }
    println(i)
}

Xcode 7のSwift 2.0の場合:

for i in (1...10).reverse() {
    print(i)
}

Swift 2.0では(1...1_000_000_000_000).reverse()のタイプReverseRandomAccessCollection<(Range<Int>)>であるため、これは正常に機能します。

var count = 0
for i in (1...1_000_000_000_000).reverse() {
    count += 1
    if count > 5 {
        break
    }
    print(i)
}

スウィフト3.0 reverse()に変更されましたreversed()

for i in (1...10).reversed() {
    print(i) // prints 10 through 1
}

3
reversedただし、コレクションをコピーできます。少なくとも、それが私がのドキュメントを理解する方法Dataです。
ラファエル

96

Swift 3用に更新

以下の答えは利用可能なオプションの要約です。ニーズに最適なものを選択してください。

reversed:範囲内の数値

進む

for index in 0..<5 {
    print(index)
}

// 0
// 1
// 2
// 3
// 4

後方

for index in (0..<5).reversed() {
    print(index)
}

// 4
// 3
// 2
// 1
// 0

reversed:の要素 SequenceType

let animals = ["horse", "cow", "camel", "sheep", "goat"]

進む

for animal in animals {
    print(animal)
}

// horse
// cow
// camel
// sheep
// goat

後方

for animal in animals.reversed() {
    print(animal)
}

// goat
// sheep
// camel
// cow
// horse

reversed:インデックスを持つ要素

コレクションを反復処理するときに、インデックスが必要になる場合があります。そのためにenumerate()は、タプルを返すを使用できます。タプルの最初の要素はインデックスで、2番目の要素はオブジェクトです。

let animals = ["horse", "cow", "camel", "sheep", "goat"]

進む

for (index, animal) in animals.enumerated() {
    print("\(index), \(animal)")
}

// 0, horse
// 1, cow
// 2, camel
// 3, sheep
// 4, goat

後方

for (index, animal) in animals.enumerated().reversed()  {
    print("\(index), \(animal)")
}

// 4, goat
// 3, sheep
// 2, camel
// 1, cow
// 0, horse

Ben Lachmanが彼の回答で述べたようにおそらくインデックス番号を増やす.enumerated().reversed()よりも、実行したいことに注意してください.reversed().enumerated()

ストライド:数値

ストライドは、範囲を使用せずに反復する方法です。2つの形式があります。コードの最後にあるコメントは、範囲バージョンがどうなるかを示しています(増分サイズが1であると仮定)。

startIndex.stride(to: endIndex, by: incrementSize)      // startIndex..<endIndex
startIndex.stride(through: endIndex, by: incrementSize) // startIndex...endIndex

進む

for index in stride(from: 0, to: 5, by: 1) {
    print(index)
}

// 0
// 1
// 2
// 3
// 4

後方

インクリメントサイズを変更して、前-1に戻ることができるようにします。

for index in stride(from: 4, through: 0, by: -1) {
    print(index)
}

// 4
// 3
// 2
// 1
// 0

tothrough違いに注意してください。

ストライド:SequenceTypeの要素

2ずつ増加

let animals = ["horse", "cow", "camel", "sheep", "goat"]

2この例では、別の可能性を示すためだけに使用しています。

for index in stride(from: 0, to: 5, by: 2) {
    print("\(index), \(animals[index])")
}

// 0, horse
// 2, camel
// 4, goat

後方

for index in stride(from: 4, through: 0, by: -1) {
    print("\(index), \(animals[index])")
}

// 4, goat
// 3, sheep 
// 2, camel
// 1, cow  
// 0, horse 

ノート


52

Swift 4以降

for i in stride(from: 5, to: 0, by: -1) {
    print(i)
}
//prints 5, 4, 3, 2, 1

for i in stride(from: 5, through: 0, by: -1) {
    print(i)
}
//prints 5, 4, 3, 2, 1, 0

28

Swift 5では、必要に応じて、問題を解決するために、4つのPlaygroundコード例のいずれかを選択できます。


#1。ClosedRange reversed()メソッドの使用

ClosedRangeというメソッドがありreversed()ます。reversed()メソッドには次の宣言があります。

func reversed() -> ReversedCollection<ClosedRange<Bound>>

コレクションの要素を逆の順序で表示するビューを返します。

使用法:

let reversedCollection = (0 ... 5).reversed()

for index in reversedCollection {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

別のRange reversed()方法として、次の方法を使用できます。

let reversedCollection = (0 ..< 6).reversed()

for index in reversedCollection {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

#2。sequence(first:next:)関数の使用

Swift標準ライブラリには、という関数が用意されていsequence(first:next:)ます。sequence(first:next:)次の宣言があります:

func sequence<T>(first: T, next: @escaping (T) -> T?) -> UnfoldFirstSequence<T>

firstレイジーアプリケーションから形成され、繰り返されたシーケンスを返しますnext

使用法:

let unfoldSequence = sequence(first: 5, next: {
    $0 > 0 ? $0 - 1 : nil
})

for index in unfoldSequence {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

#3。stride(from:through:by:)関数の使用

Swift標準ライブラリには、という関数が用意されていstride(from:through:by:)ます。stride(from:through:by:)次の宣言があります:

func stride<T>(from start: T, through end: T, by stride: T.Stride) -> StrideThrough<T> where T : Strideable

開始値から終了値に向かって、場合によっては終了値を含み、指定された量だけステップを返します。

使用法:

let sequence = stride(from: 5, through: 0, by: -1)

for index in sequence {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

別の方法として、次のものを使用できますstride(from:to:by:)

let sequence = stride(from: 5, to: -1, by: -1)

for index in sequence {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

#4。AnyIterator init(_:)初期化子を使用する

AnyIteratorというイニシャライザがありますinit(_:)init(_:)次の宣言があります:

init(_ body: @escaping () -> AnyIterator<Element>.Element?)

指定されたクロージャーをnext()メソッドでラップするイテレーターを作成します。

使用法:

var index = 5

guard index >= 0 else { fatalError("index must be positive or equal to zero") }

let iterator = AnyIterator({ () -> Int? in
    defer { index = index - 1 }
    return index >= 0 ? index : nil
})

for index in iterator {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

必要に応じて、拡張メソッドを作成しIntてイテレータをラップすることにより、前のコードをリファクタリングできます。

extension Int {

    func iterateDownTo(_ endIndex: Int) -> AnyIterator<Int> {
        var index = self
        guard index >= endIndex else { fatalError("self must be greater than or equal to endIndex") }

        let iterator = AnyIterator { () -> Int? in
            defer { index = index - 1 }
            return index >= endIndex ? index : nil
        }
        return iterator
    }

}

let iterator = 5.iterateDownTo(0)

for index in iterator {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

sequence(first:5、next:{($ 0> 0)?($ 0-1):nil})//($ 0-1> = 0)よりも簡単
SirEnder

27

Swift 2.0以降の場合、範囲コレクションに逆を適用する必要があります

for i in (0 ..< 10).reverse() {
  // process
}

Swift 3.0では.reversed()に名前が変更されました



5

Swift 4.0

for i in stride(from: 5, to: 0, by: -1) {
    print(i) // 5,4,3,2,1
}

to値を含める場合:

for i in stride(from: 5, through: 0, by: -1) {
    print(i) // 5,4,3,2,1,0
}

3

配列Arrayまたはより一般的にはany SequenceType)を逆に反復処理したい場合。追加のオプションがいくつかあります。

最初にreverse()、配列を作成し、通常どおりにループすることができます。ただしenumerate()、オブジェクトとインデックスを含むタプルを出力するため、私は多くの時間を使用することを好みます。

ここで注意すべきことの1つは、これらを正しい順序で呼び出すことが重要であることです。

for (index, element) in array.enumerate().reverse()

インデックスを降順で生成します(これは私が通常期待するものです)。一方:

for (index, element) in array.reverse().enumerate()(これはNSArrayのより近い一致ですreverseEnumerator

配列を逆方向にたどりますが、昇順のインデックスを出力します。


3

Swift 2.2、Xcode 7.3(10、June、2016)の場合:

for (index,number) in (0...10).enumerate() {
    print("index \(index) , number \(number)")
}

for (index,number) in (0...10).reverse().enumerate() {
    print("index \(index) , number \(number)")
}

出力:

index 0 , number 0
index 1 , number 1
index 2 , number 2
index 3 , number 3
index 4 , number 4
index 5 , number 5
index 6 , number 6
index 7 , number 7
index 8 , number 8
index 9 , number 9
index 10 , number 10


index 0 , number 10
index 1 , number 9
index 2 , number 8
index 3 , number 7
index 4 , number 6
index 5 , number 5
index 6 , number 4
index 7 , number 3
index 8 , number 2
index 9 , number 1
index 10 , number 0

2

while代わりにC-Style ループの使用を検討できます。これはSwift 3でうまく機能します:

var i = 5 
while i > 0 { 
    print(i)
    i -= 1
}

2

値を簡単に反転するには、reversed()メソッドを使用できます。

var i:Int
for i in 1..10.reversed() {
    print(i)
}

reverse()メソッドは値を逆にします。


既存の回答と同じ回答を追加するのはなぜですか?(例:@ Rohit's。)
Davor Cubranic

1
var sum1 = 0
for i in 0...100{
    sum1 += i
}
print (sum1)

for i in (10...100).reverse(){
    sum1 /= i
}
print(sum1)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.