Döngü için hızlı bir şekilde ters sırada nasıl yinelenir?


187

For loop'u Playground'da kullandığımda, for loop'un ilk parametresini en yüksek değer olarak değiştirene kadar her şey iyi çalıştı. (azalan sırada yinelenir)

Bu bir hata mı? Başkası var mı?

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

Yürütülecek yineleme sayısını gösteren sayaç devam ediyor ...

resim açıklamasını buraya girin



1
C tarzı döngüler bırakmak için böyle parlak bir karar. Onları geri getir
Joel Teply

Swift 5 ile ters sırayla yinelemenin 4 farklı yolunu gösteren cevabımı görün .
Imanou Petit

Yanıtlar:


230

Xcode 6 beta 4, bir adımdan başka bir adımla aralıklarda yineleme yapmak için iki işlev ekledi: stride(from: to: by:)özel aralıklarla kullanılan vestride(from: through: by:) kullanılan ve kapsayıcı aralıklarla kullanılan.

Bir aralıkta ters sırayla yinelemek için, bunlar aşağıdaki gibi kullanılabilir:

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

Bunların hiçbirinin bir Rangeüye işlevi olmadığını unutmayın . Bunlar, a StrideToveya bir StrideThroughyapı döndüren ,Range .

Bu yanıtın önceki bir sürümü beta 4'te kaldırılan yapının by()üye işlevini kullanıyordu. Bunun Rangenasıl çalıştığını görmek istiyorsanız düzenleme geçmişini kontrol edin.


26
Swift 2.0 ile şimdi: 5.stride(to: 1, by: -1)veya5.stride(through: 1, by: -1)
Binarian

6
Swift 3.0 ile özgür bir işlev olarak adım atmaya geri döndük.
Cezar

@ Bu makul ve güvenli bir seçimdir. Size sık sık R programcılarının :dolaylı olarak yinelenen operatörü tarafından tetiklendiğini söyleyemem , döngülerin kendilerinin atlayacağını düşündüklerinde yürütülmelerine neden olur. Etkileşimli kullanım için çok uygundur, ancak stil kılavuzlarının kullanmaya karşı önerdiği noktaya kadar komut dosyalarında son derece hatalıdır .
Davor Cubranic

213

Geriye doğru yinelemek için aralığa ters fonksiyon uygulayın:

İçin Swift 1.2 ve öncesi:

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

Ayrıca yarı açık aralıklarla çalışır:

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

Not: reverse(1...10)bir tür dizi oluşturur [Int], bu nedenle bu küçük aralıklar için iyi olsa da, lazyaşağıda gösterildiği gibi kullanmak akıllıca olur veya stridearalığınız büyükse kabul edilen cevabı düşünün .


Büyük bir dizi oluşturmaktan kaçınmak için lazyile birlikte kullanın reverse(). Aşağıdaki test, bir Trilyon Ints ile bir dizi oluşturmadığını gösteren bir Oyun Alanında verimli bir şekilde çalışır !

Ölçek:

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

İçin Swift 2.0 Xcode 7'de:

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

Swift 2.0'da (1...1_000_000_000_000).reverse()tür olduğunu unutmayın ReverseRandomAccessCollection<(Range<Int>)>, bu yüzden bu iyi çalışır:

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

İçin Swift 3.0 reverse() olarak yeniden adlandırıldı reversed():

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

3
reversedyine de koleksiyonu kopyalayabilir. En azından, buradaki belgeleri anlıyorum Data.
Raphael

96

Swift 3 için güncellendi

Aşağıdaki cevap, mevcut seçeneklerin bir özetidir. İhtiyaçlarınıza en uygun olanı seçin.

reversed: aralıktaki sayılar

ileri

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

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

Geriye

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

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

reversed: içindeki elemanlar SequenceType

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

ileri

for animal in animals {
    print(animal)
}

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

Geriye

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

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

reversed: indeksli elemanlar

Bazen bir koleksiyon boyunca yineleme yaparken bir indeks gerekebilir. Bunun için enumerate()bir tuple döndüren kullanabilirsiniz . Grubun ilk elemanı dizindir ve ikinci eleman nesnedir.

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

ileri

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

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

Geriye

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

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

Ben Lachman'ın cevabında belirttiği gibi , muhtemelen yapmak .enumerated().reversed()yerine.reversed().enumerated() (endeks numaralarını artıracak) yapmak istediğinizi unutmayın.

adım: sayılar

Adım, bir aralık kullanmadan yinelemenin yoludur. İki form vardır. Kodun sonundaki yorumlar aralık sürümünün ne olacağını gösterir (artış boyutunun 1 olduğu varsayılarak).

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

ileri

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

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

Geriye

Artış boyutunu değiştirmek -1geriye doğru gitmenizi sağlar.

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

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

toVe throughfarkını not edin .

stride: SequenceType öğelerinin öğeleri

2'lik adımlarla ileri sar

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

2Bu örnekte sadece başka bir olasılık göstermek için kullanıyorum .

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

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

Geriye

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

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

notlar


52

Swift 4 sonrası

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 ile, ihtiyaçlarınıza göre, sorununuzu çözmek için aşağıdaki Dört Oyun Alanı kodu örneğinden birini seçebilirsiniz .


# 1. ClosedRange reversed()Yöntemi kullanarak

ClosedRangeadlı bir yöntem var reversed(). reversed()yöntemi aşağıdaki bildirime sahiptir:

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

Koleksiyonun öğelerini ters sırada sunan bir görünüm döndürür.

Kullanımı:

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

for index in reversedCollection {
    print(index)
}

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

Alternatif olarak, Range reversed()yöntemi kullanabilirsiniz :

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

for index in reversedCollection {
    print(index)
}

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

# 2. sequence(first:next:)Fonksiyonu kullanarak

Swift Standart Kütüphanesi adlı bir işlev sağlar sequence(first:next:). sequence(first:next:)aşağıdaki beyanı içerir:

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

Öğesinden oluşturulan firstve tekrarlanan tembel uygulamalardan oluşan bir dizi döndürür next.

Kullanımı:

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:)Fonksiyonu kullanma

Swift Standart Kütüphanesi adlı bir işlev sağlar stride(from:through:by:). stride(from:through:by:)aşağıdaki beyanı içerir:

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

Belirtilen miktara göre bir başlangıç ​​değerinden bir bitiş değerine doğru olan ve muhtemelen bir bitiş değerine sahip bir dizi döndürür.

Kullanımı:

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

for index in sequence {
    print(index)
}

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

Alternatif olarak şunları kullanabilirsiniz 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(_:)Başlatıcı kullanma

AnyIteratoradlı bir başlatıcıya sahip init(_:). init(_:)aşağıdaki beyanı içerir:

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

Verilen kapamayı next()yöntemine saran bir yineleyici oluşturur .

Kullanımı:

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

Gerekirse, Intyineleyicinizi bir genişletme yöntemi oluşturarak ve yineleyicinizi içine sararak önceki kodu yeniden düzenleyebilirsiniz :

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

sekans (ilk: 5, sonraki: {($ 0> 0)? (0 - 1 $: nil}) // ($ 0 - 1> = 0) 'dan daha basit
13

27

Swift 2.0 ve üstü için bir dizi koleksiyonuna ters uygulamanız gerekir

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

Swift 3.0'da .reversed () olarak yeniden adlandırıldı


9

Swift 4 ve sonuncusunda

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

5

Swift 4.0

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

toDeğeri eklemek istiyorsanız :

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

3

Kişi bir dizi üzerinden yineleme yapmak istiyorsa ( Arrayveya daha genel olarakSequenceType ) üzerinden tersini . Birkaç ek seçeneğiniz var.

İlk reverse()olarak dizi ve normal üzerinden döngü yapabilirsiniz . Ancak kullanmayı tercih ediyorumenumerate() nesne ve dizin içeren bir tuple çıktı beri çoğu zaman .

Burada dikkat edilmesi gereken tek şey, bunları doğru sırayla çağırmanın önemli olduğudur:

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

indeksleri azalan sırada verir (genellikle beklediğim budur). buna karşılık:

for (index, element) in array.reverse().enumerate() (NSArray's ile daha yakın bir eşleşme reverseEnumerator )

diziyi geriye doğru yürür, ancak artan dizinler çıkarır.


3

Swift 2.2, Xcode 7.3 (10, Haziran, 2016) için:

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)")
}

Çıktı :

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

Bunun whileyerine C Stili döngüsünü kullanmayı düşünebilirsiniz . Swift 3'te bu iyi çalışıyor:

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

2

Değerleri kolayca tersine çevirmek için reversed () yöntemini kullanabilirsiniz.

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

Reversed () yöntemi değerleri tersine çevirir.


Neden zaten mevcut olanla aynı cevabı ekleyesiniz? (Örn, @ 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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.