Come iterare per il ciclo in ordine inverso in rapido?


187

Quando uso il ciclo for in Playground, tutto ha funzionato bene, fino a quando non ho cambiato il primo parametro di for loop per ottenere il valore più alto. (ripetuto in ordine decrescente)

è un insetto? Qualcun altro ce l'aveva?

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

Il contatore che mostra il numero di iterazioni che saranno esecuzioni continua a spuntare ...

inserisci qui la descrizione dell'immagine


3
possibile duplicato di Reverse Range in Swift
Matt Gibson,

1
Una decisione così brillante da eliminare i loop in stile c. Riportali indietro
Joel Teply,

Vedi la mia risposta con Swift 5 che mostra fino a 4 modi diversi per scorrere in ordine inverso.
Imanou Petit,

Risposte:


230

Xcode 6 beta 4 ha aggiunto due funzioni per scorrere su intervalli con un passaggio diverso da uno:, stride(from: to: by:)che viene utilizzato con intervalli esclusivi e stride(from: through: by:), che viene utilizzato con intervalli inclusivi.

Per scorrere su un intervallo in ordine inverso, possono essere utilizzati come di seguito:

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

Si noti che nessuno di questi è una Rangefunzione membro. Sono funzioni globali che restituiscono una StrideToo una StrideThroughstruttura, che sono definite in modo diverso daRange struttura.

Una versione precedente di questa risposta utilizzava la by()funzione membro della Rangestruttura, che era stata rimossa in versione beta 4. Se vuoi vedere come ha funzionato, controlla la cronologia delle modifiche.


26
Con Swift 2.0 è ora: 5.stride(to: 1, by: -1)oppure5.stride(through: 1, by: -1)
Binarian,

6
Con Swift 3.0 siamo tornati a camminare come una funzione gratuita.
Cezar,

@Shaun è una scelta ragionevole e sicura. Non posso dirti spesso che i programmatori R sono inciampati dal suo :operatore che scorre implicitamente verso il basso, causando l'esecuzione dei loro loop quando pensavano che li avrebbe saltati. È molto conveniente per l'uso interattivo, ma è estremamente soggetto a errori negli script, al punto che le guide di stile sconsigliano di usarlo .
Assapora Cubranic il

213

Applicare la funzione inversa all'intervallo per scorrere indietro:

Per Swift 1.2 e precedenti:

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

Funziona anche con gamme semiaperte:

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

Nota: reverse(1...10)crea una matrice di tipo [Int], quindi sebbene ciò possa andare bene per piccoli intervalli, sarebbe saggio usare lazycome mostrato di seguito o considerare la striderisposta accettata se il tuo intervallo è ampio.


Per evitare di creare un array di grandi dimensioni, utilizzare lazyinsieme a reverse(). Il seguente test viene eseguito in modo efficiente in un Playground dimostrando che non sta creando un array con un trilione di Ints!

Test:

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

Per Swift 2.0 in Xcode 7:

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

Nota che in Swift 2.0 (1...1_000_000_000_000).reverse()è di tipo ReverseRandomAccessCollection<(Range<Int>)>, quindi funziona bene:

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

Per Swift 3.0 reverse() è stato rinominato in reversed():

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

3
reversedpotrebbe copiare la raccolta, comunque. Almeno, è così che capisco la documentazione Data.
Raffaello,

96

Aggiornato per Swift 3

La risposta di seguito è un riepilogo delle opzioni disponibili. Scegli quello più adatto alle tue esigenze.

reversed: numeri in un intervallo

Inoltrare

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

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

a rovescio

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

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

reversed: elementi in SequenceType

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

Inoltrare

for animal in animals {
    print(animal)
}

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

a rovescio

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

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

reversed: elementi con un indice

A volte è necessario un indice quando si scorre una raccolta. Per questo puoi usare enumerate(), che restituisce una tupla. Il primo elemento della tupla è l'indice e il secondo elemento è l'oggetto.

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

Inoltrare

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

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

a rovescio

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

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

Nota che, come ha notato Ben Lachman nella sua risposta , probabilmente vorrai fare .enumerated().reversed()piuttosto che.reversed().enumerated() (il che farebbe aumentare i numeri dell'indice).

passo: numeri

Stride è il modo di iterare senza usare un intervallo. Esistono due forme. I commenti alla fine del codice mostrano quale sarebbe la versione dell'intervallo (supponendo che la dimensione dell'incremento sia 1).

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

Inoltrare

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

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

a rovescio

La modifica della dimensione dell'incremento -1consente di tornare indietro.

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

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

Si noti la toe throughdifferenza.

falcata: elementi di SequenceType

Avanti con incrementi di 2

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

Sto usando 2in questo esempio solo per mostrare un'altra possibilità.

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

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

a rovescio

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

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

Appunti


52

Passa da 4 in poi

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

Con Swift 5, in base alle tue esigenze, puoi scegliere uno dei seguenti quattro esempi di codice Playground per risolvere il tuo problema.


# 1. Usando il ClosedRange reversed()metodo

ClosedRangeha un metodo chiamato reversed(). reversed()Il metodo ha la seguente dichiarazione:

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

Restituisce una vista che presenta gli elementi della raccolta in ordine inverso.

Uso:

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

for index in reversedCollection {
    print(index)
}

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

In alternativa, è possibile utilizzare il Range reversed()metodo:

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

for index in reversedCollection {
    print(index)
}

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

# 2. Utilizzando la sequence(first:next:)funzione

Swift Standard Library fornisce una funzione chiamata sequence(first:next:). sequence(first:next:)ha la seguente dichiarazione:

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

Restituisce una sequenza formata da firste ripetute applicazioni pigre di next.

Uso:

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. Utilizzando la stride(from:through:by:)funzione

Swift Standard Library fornisce una funzione chiamata stride(from:through:by:). stride(from:through:by:)ha la seguente dichiarazione:

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

Restituisce una sequenza da un valore iniziale verso, e possibilmente includendo, un valore finale, avanzando dell'importo specificato.

Uso:

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

for index in sequence {
    print(index)
}

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

In alternativa, puoi usare 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. Utilizzando l' AnyIterator init(_:)inizializzatore

AnyIteratorha un inizializzatore chiamato init(_:). init(_:)ha la seguente dichiarazione:

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

Crea un iteratore che avvolge la chiusura specificata nel suo next()metodo.

Uso:

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

Se necessario, puoi riformattare il codice precedente creando un metodo di estensione Inte avvolgendo il tuo iteratore in esso:

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

sequenza (prima: 5, successiva: {($ 0> 0)? ($ 0 - 1): zero}) // è più semplice di ($ 0 - 1> = 0)
SirEnder

27

Per Swift 2.0 e versioni successive è necessario applicare il contrario su una raccolta di intervalli

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

È stato rinominato in .reversed () in Swift 3.0


9

In Swift 4 e quest'ultimo

    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
}

Se vuoi includere il tovalore:

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

3

Se si desidera eseguire l'iterazione attraverso un array ( Arrayo più in generale qualsiasi SequenceType) al contrario. Hai alcune opzioni aggiuntive.

Per prima cosa puoi eseguire reverse()l'array e scorrere in modo normale. Tuttavia preferisco usare enumerate()gran parte del tempo poiché genera una tupla contenente l'oggetto e il suo indice.

L'unica cosa da notare qui è che è importante chiamarli nell'ordine giusto:

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

produce indici in ordine decrescente (che è quello che generalmente mi aspetto). mentre:

for (index, element) in array.reverse().enumerate() (che è una corrispondenza più vicina a quella di NSArray reverseEnumerator )

cammina l'array all'indietro ma genera indici in ordine crescente.


3

come per Swift 2.2, Xcode 7.3 (10 giugno 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)")
}

Produzione :

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

Puoi prendere in considerazione l'utilizzo del whileloop C-Style . Funziona bene in Swift 3:

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

2

È possibile utilizzare il metodo reverse () per invertire facilmente i valori.

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

Il metodo reversed () inverte i valori.


Perché dovresti aggiungere una risposta identica a quella già esistente? (Ad esempio, @ 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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.