Bagaimana cara mengulang untuk loop dalam urutan terbalik dalam cepat?

187

Ketika saya menggunakan loop untuk di Playground, semuanya bekerja dengan baik, sampai saya mengubah parameter pertama untuk loop menjadi nilai tertinggi. (iterasi dalam urutan menurun)

Apakah ini bug? Apakah ada orang lain yang memilikinya?

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

Penghitung yang menampilkan jumlah iterasi yang akan dieksekusi terus berdetak ...

masukkan deskripsi gambar di sini

Krishnan
sumber
3
kemungkinan duplikat Reverse Range in Swift
Matt Gibson
1
Suatu keputusan yang brilian untuk menjatuhkan loop gaya. Bawa mereka kembali
Joel Teply
Lihat jawaban saya dengan Swift 5 yang menunjukkan hingga 4 cara berbeda untuk beralih dalam urutan terbalik.
Imanou Petit

Jawaban:

230

Xcode 6 beta 4 menambahkan dua fungsi untuk beralih pada rentang dengan langkah selain satu:, stride(from: to: by:)yang digunakan dengan rentang eksklusif dan stride(from: through: by:), yang digunakan dengan rentang inklusif.

Untuk beralih pada rentang dalam urutan terbalik, mereka dapat digunakan seperti di bawah ini:

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

Perhatikan bahwa keduanya bukan merupakan Rangefungsi anggota. Mereka adalah fungsi global yang mengembalikan salah satu StrideToatau sebuah StrideThroughstruct, yang didefinisikan secara berbeda dari Rangestruct.

Versi sebelumnya dari jawaban ini menggunakan by()fungsi anggota Rangestruct, yang telah dihapus dalam versi beta 4. Jika Anda ingin melihat cara kerjanya, periksa riwayat edit.

Cezar
sumber
26
Dengan Swift 2.0 sekarang: 5.stride(to: 1, by: -1)atau5.stride(through: 1, by: -1)
Binarian
6
Dengan Swift 3.0 kita kembali ke fungsi bebas.
Cezar
@Shaun itu adalah pilihan yang masuk akal dan aman. Saya tidak bisa memberi tahu Anda bahwa programmer R sering tersandung oleh :operatornya secara implisit berulang ke bawah, menyebabkan loop mereka untuk mengeksekusi ketika mereka berpikir itu akan melompati mereka. Ini sangat nyaman untuk penggunaan interaktif, tetapi sangat rawan kesalahan dalam skrip, ke titik di mana panduan gaya merekomendasikan untuk tidak menggunakannya .
Davor Cubranic
213

Terapkan fungsi terbalik ke rentang untuk beralih mundur:

Untuk Swift 1.2 dan sebelumnya:

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

Ini juga bekerja dengan rentang setengah terbuka:

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

Catatan: reverse(1...10)membuat larik tipe [Int], jadi meskipun ini mungkin baik untuk rentang kecil, akan lebih bijaksana untuk menggunakan lazyseperti yang ditunjukkan di bawah ini atau mempertimbangkan stridejawaban yang diterima jika rentang Anda besar.


Untuk menghindari membuat array besar, gunakan lazybersama reverse(). Tes berikut berjalan efisien di Playground yang menunjukkan bahwa itu tidak membuat array dengan satu triliun Ints!

Uji:

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

Untuk Swift 2.0 di Xcode 7:

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

Perhatikan bahwa dalam Swift 2.0, (1...1_000_000_000_000).reverse()bertipe ReverseRandomAccessCollection<(Range<Int>)>, jadi ini berfungsi dengan baik:

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

For Swift 3.0 reverse() telah diubah namanya menjadi reversed():

for i in (1...10).reversed() {
    print(i) // prints 10 through 1
}
vacawama
sumber
3
reverseddapat menyalin koleksi. Setidaknya, begitulah cara saya memahami dokumentasi Data.
Raphael
96

Diperbarui untuk Swift 3

Jawaban di bawah ini adalah ringkasan dari opsi yang tersedia. Pilih salah satu yang paling sesuai dengan kebutuhan Anda.

reversed: angka dalam suatu rentang

Meneruskan

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

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

Ke belakang

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

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

reversed: elemen dalam SequenceType

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

Meneruskan

for animal in animals {
    print(animal)
}

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

Ke belakang

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

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

reversed: elemen dengan indeks

Terkadang indeks diperlukan saat iterasi melalui koleksi. Untuk itu Anda dapat menggunakan enumerate(), yang mengembalikan tupel. Elemen pertama dari tuple adalah indeks dan elemen kedua adalah objek.

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

Meneruskan

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

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

Ke belakang

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

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

Perhatikan bahwa seperti yang dicatat Ben Lachman dalam jawabannya , Anda mungkin ingin melakukan .enumerated().reversed()alih - alih .reversed().enumerated()(yang akan membuat angka indeks meningkat).

melangkah: angka

Langkahnya adalah cara untuk beralih tanpa menggunakan rentang. Ada dua bentuk. Komentar di akhir kode menunjukkan seperti apa versi jangkauan (dengan asumsi ukuran kenaikan adalah 1).

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

Meneruskan

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

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

Ke belakang

Mengubah ukuran kenaikan untuk -1memungkinkan Anda untuk mundur.

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

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

Perhatikan todan throughperbedaan.

langkahnya: elemen SequenceType

Maju dengan selisih 2

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

Saya menggunakan 2dalam contoh ini hanya untuk menunjukkan kemungkinan lain.

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

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

Ke belakang

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

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

Catatan

Suragch
sumber
52

Cepat 4 dan seterusnya

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
Irfan
sumber
28

Dengan Swift 5, sesuai dengan kebutuhan Anda, Anda dapat memilih salah satu dari empat contoh kode Playground berikut untuk menyelesaikan masalah Anda.


# 1. Menggunakan ClosedRange reversed()metode

ClosedRangememiliki metode yang disebut reversed(). reversed()Metode memiliki deklarasi berikut:

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

Mengembalikan tampilan yang menyajikan elemen-elemen koleksi dalam urutan terbalik.

Pemakaian:

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

for index in reversedCollection {
    print(index)
}

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

Sebagai alternatif, Anda dapat menggunakan Range reversed()metode:

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

for index in reversedCollection {
    print(index)
}

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

# 2. Menggunakan sequence(first:next:)fungsi

Swift Standard Library menyediakan fungsi yang disebut sequence(first:next:). sequence(first:next:)memiliki deklarasi berikut:

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

Mengembalikan urutan yang terbentuk dari firstdan mengulangi aplikasi malas dari next.

Pemakaian:

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. Menggunakan stride(from:through:by:)fungsi

Swift Standard Library menyediakan fungsi yang disebut stride(from:through:by:). stride(from:through:by:)memiliki deklarasi berikut:

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

Mengembalikan urutan dari nilai awal menuju, dan mungkin termasuk, nilai akhir, melangkah dengan jumlah yang ditentukan.

Pemakaian:

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

for index in sequence {
    print(index)
}

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

Sebagai alternatif, Anda dapat menggunakan 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 Menggunakan AnyIterator init(_:)inisialisasi

AnyIteratormemiliki penginisialisasi yang disebut init(_:). init(_:)memiliki deklarasi berikut:

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

Membuat iterator yang membungkus penutupan yang diberikan dalam next()metodenya.

Pemakaian:

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
*/

Jika perlu, Anda dapat memperbaiki kode sebelumnya dengan membuat metode ekstensi untuk Intdan membungkus iterator Anda di dalamnya:

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
*/
Imanou Petit
sumber
urutan (pertama: 5, berikutnya: {($ 0> 0)? ($ 0 - 1): nil}) // lebih sederhana daripada ($ 0 - 1> = 0)
SirEnder
27

Untuk Swift 2.0 dan di atasnya, Anda harus menerapkan pembalikan pada koleksi rentang

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

Ini telah diubah namanya menjadi .reversed () di Swift 3.0

Andrew Luca
sumber
9

Dalam Swift 4 dan yang terakhir

    let count = 50//For example
    for i in (1...count).reversed() {
        print(i)
    }
Rohit Sisodia
sumber
5

Cepat 4.0

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

Jika Anda ingin memasukkan tonilainya:

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

Jika seseorang ingin beralih melalui array ( Arrayatau lebih umum apa saja SequenceType) secara terbalik. Anda memiliki beberapa opsi tambahan.

Pertama, Anda dapat reverse()array dan loop melalui itu seperti biasa. Namun saya lebih suka menggunakan enumerate()banyak waktu karena menghasilkan tuple yang berisi objek dan indeksnya.

Satu hal yang perlu diperhatikan di sini adalah penting untuk menyebutnya dengan urutan yang benar:

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

menghasilkan indeks dalam urutan menurun (yang biasanya saya harapkan). sedangkan:

for (index, element) in array.reverse().enumerate()(yang merupakan pertandingan yang lebih dekat dengan NSArray reverseEnumerator)

berjalan array ke belakang tetapi menampilkan indeks naik.

Ben Lachman
sumber
3

seperti untuk Swift 2.2, Xcode 7.3 (10, Juni, 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)")
}

Output:

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
PeiweiChen
sumber
2

Anda dapat mempertimbangkan menggunakan whileloop C-Style sebagai gantinya. Ini berfungsi dengan baik di Swift 3:

var i = 5 
while i > 0 { 
    print(i)
    i -= 1
}
Nitin Nain
sumber
2

Anda dapat menggunakan metode terbalik () untuk dengan mudah membalikkan nilai.

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

Metode terbalik () membalikkan nilai.

SIDHARTH PU
sumber
Mengapa Anda menambahkan jawaban yang identik dengan yang sudah ada? (Misalnya, @ Rohit.)
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)
Abo3atef
sumber