¿Cómo iterar para el bucle en orden inverso en swift?

Cuando uso el bucle for en Playground, todo funcionó bien, hasta que cambié el primer parámetro de for loop para que fuera el valor más alto. (iterado en orden descendente)

¿Es esto un error? ¿Alguien más lo tiene?

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

El contador que muestra el número de iteraciones que serán ejecuciones sigue marcando …

enter image description here

Xcode 6 beta 4 agregó dos funciones para iterar en rangos con un paso que no sea uno: stride(from: to: by:) , que se usa con rangos exclusivos y stride(from: through: by:) , que se usa con inclusivo rangos.

Para iterar en un rango en orden inverso, se pueden usar de la siguiente manera:

 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 

Tenga en cuenta que ninguno de ellos es una función miembro de Range . Son funciones globales que devuelven una StrideTo o StrideThrough , que se definen de forma diferente a la estructura Range .

Una versión anterior de esta respuesta utilizaba la función miembro de by() de la estructura de Range , que se eliminó en la versión beta 4. Si desea ver cómo funcionaba, consulte el historial de edición.

Aplicar la función inversa al rango para iterar hacia atrás:

Para Swift 1.2 y versiones anteriores:

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

También funciona con rangos medio abiertos:

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

Nota: reverse(1...10) crea una matriz de tipo [Int] , por lo que aunque podría ser adecuado para rangos pequeños, sería aconsejable usar lazy como se muestra a continuación o considerar la respuesta de stride aceptada si su rango es grande .


Para evitar crear una matriz grande, use lazy junto con reverse() . La siguiente prueba se ejecuta de manera eficiente en un patio de recreo y muestra que no está creando una matriz con un trillón de Int .

Prueba:

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

Para Swift 2.0 en Xcode 7:

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

Tenga en cuenta que en Swift 2.0, (1...1_000_000_000_000).reverse() es del tipo ReverseRandomAccessCollection< (Range)> , así que funciona bien:

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

Para Swift 3.0 reverse() ha cambiado el nombre a reversed() :

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

Actualizado para Swift 3

La respuesta a continuación es un resumen de las opciones disponibles. Elija el que mejor se adapte a sus necesidades.

reversed : números en un rango

Adelante

 for index in 0..<5 { print(index) } // 0 // 1 // 2 // 3 // 4 

Hacia atrás

 for index in (0..<5).reversed() { print(index) } // 4 // 3 // 2 // 1 // 0 

reversed : elementos en SequenceType

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

Adelante

 for animal in animals { print(animal) } // horse // cow // camel // sheep // goat 

Hacia atrás

 for animal in animals.reversed() { print(animal) } // goat // sheep // camel // cow // horse 

reversed : elementos con un índice

Algunas veces se necesita un índice cuando se itera a través de una colección. Para eso puedes usar enumerate() , que devuelve una tupla. El primer elemento de la tupla es el índice y el segundo elemento es el objeto.

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

Adelante

 for (index, animal) in animals.enumerated() { print("\(index), \(animal)") } // 0, horse // 1, cow // 2, camel // 3, sheep // 4, goat 

Hacia atrás

 for (index, animal) in animals.enumerated().reversed() { print("\(index), \(animal)") } // 4, goat // 3, sheep // 2, camel // 1, cow // 0, horse 

Tenga en cuenta que, como señaló Ben Lachman en su respuesta , probablemente desee hacer .enumerated().reversed() lugar de .reversed().enumerated() (lo que haría que los números de índice aumenten).

zancada: números

Stride es una forma de iterar sin usar un rango. Hay dos formas. Los comentarios al final del código muestran cuál sería la versión de rango (suponiendo que el tamaño de incremento es 1).

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

Adelante

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

Hacia atrás

Cambiar el tamaño del incremento a -1 permite retroceder.

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

Tenga en cuenta la diferencia directa.

zancada: elementos de SequenceType

Reenviar por incrementos de 2

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

Estoy usando 2 en este ejemplo solo para mostrar otra posibilidad.

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

Hacia atrás

 for index in stride(from: 4, through: 0, by: -1) { print("\(index), \(animals[index])") } // 4, goat // 3, sheep // 2, camel // 1, cow // 0, horse 

Notas

  • @matt tiene una solución interesante en la que define su propio operador inverso y lo llama >>> . No requiere mucho código para definir y se usa así:

     for index in 5>>>0 { print(index) } // 4 // 3 // 2 // 1 // 0 
  • Echa un vistazo a C-Style for Loops Eliminado de Swift 3

Swift 4 en adelante

 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 

Para Swift 2.0 y superior, debe aplicar el reverso en una colección de rango

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

Se ha cambiado el nombre a .reversed () en Swift 3.0

Con Swift 3, de acuerdo con sus necesidades, puede elegir una de las ocho implementaciones de códigos de Playground siguientes para resolver su problema.


# 1. Uso del método CountableClosedRange reversed()

CountableClosedRange tiene un método llamado reversed() . reversed() método reversed() tiene la siguiente statement:

 func reversed() -> ReversedRandomAccessCollection> 

Devuelve una vista que presenta los elementos de la colección en orden inverso.

Uso:

 let reversedRandomAccessCollection = (0 ... 5).reversed() for index in reversedRandomAccessCollection { print(index) } /* Prints: 5 4 3 2 1 0 */ 

# 2. Usando el método CountableRange reversed()

CountableRange tiene un método llamado reversed() . reversed() método reversed() tiene la siguiente statement:

 func reversed() -> ReversedRandomAccessCollection> 

Devuelve una vista que presenta los elementos de la colección en orden inverso.

Uso:

 let reversedRandomAccessCollection = (0 ..< 6).reversed() for index in reversedRandomAccessCollection { print(index) } /* Prints: 5 4 3 2 1 0 */ 

# 3. Usar la función de sequence(first:next:)

Swift Standard Library proporciona una función llamada sequence(first:next:) . sequence(first:next:) tiene la siguiente statement:

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

Devuelve una secuencia formada a partir de aplicaciones perezosas first y repetida de la 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 */ 

# 4. Uso de la función stride(from:through:by:)

Swift Standard Library proporciona una función llamada stride(from:through:by:) . stride(from:through:by:) tiene la siguiente statement:

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

Devuelve la secuencia de valores (self, self + stride, self + 2 * stride, … last) donde last es el último valor en la progresión menor o igual que end .

Uso:

 let sequence = stride(from: 5, through: 0, by: -1) for index in sequence { print(index) } /* Prints: 5 4 3 2 1 0 */ 

# 5. Uso de la función stride(from:to:by:)

Swift Standard Library proporciona una función llamada stride(from:to:by:) . stride(from:to:by:) tiene la siguiente statement:

 func stride(from start: T, to end: T, by stride: T.Stride) -> StrideTo where T : Strideable 

Devuelve la secuencia de valores (self, self + stride, self + 2 * stride, … last) donde last es el último valor en la progresión que es menor que end .

Uso:

 let sequence = stride(from: 5, to: -1, by: -1) for index in sequence { print(index) } /* Prints: 5 4 3 2 1 0 */ 

# 6. Usar el AnyIterator init(_:) AnyIterator

AnyIterator tiene un inicializador llamado init(_:) . init(_:) tiene la siguiente statement:

 init(_ base: I) where I : IteratorProtocol, I.Element == Element 

Crea un iterador que envuelve un iterador base pero cuyo tipo depende solo del tipo de elemento del iterador base.

Uso:

 var index = 5 guard index >= 0 else { fatalError("index must be positive or equal to zero") } let iterator = AnyIterator({ defer { index = index - 1 } return index >= 0 ? index : nil }) for index in iterator { print(index) } /* Prints: 5 4 3 2 1 0 */ 

# 7. Usar el AnyIterator init(_:) AnyIterator

AnyIterator tiene un inicializador llamado init(_:) . init(_:) tiene la siguiente statement:

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

Crea un iterador que ajusta el cierre dado en su método next() .

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

# 8. Usar un método de extensión Int personalizado

Puede refactorizar el código anterior creando un método de extensión para Int y envolviendo su iterador en él:

 extension Int { func iterateDownTo(_ endIndex: Int) -> AnyIterator { 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 */ 

En Swift 4 y último

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

Swift 4.0

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

Si desea incluir el valor a:

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

Si uno quiere iterar a través de una matriz ( Array o más generalmente cualquier SequenceType ) en reversa. Tienes algunas opciones adicionales.

Primero puede reverse() la matriz y recorrerla como de costumbre. Sin embargo, prefiero usar enumerate() parte del tiempo ya que produce una tupla que contiene el objeto y su índice.

Lo único que hay que notar aquí es que es importante llamarlos en el orden correcto:

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

arroja índices en orden descendente (que es lo que generalmente espero). mientras:

for (index, element) in array.reverse().enumerate() (que es una coincidencia más cercana con reverseEnumerator de NSArray)

camina la matriz hacia atrás pero muestra índices ascendentes.

en cuanto a Swift 2.2, Xcode 7.3 (10, junio de 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)") } 

Salida:

 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 
 var sum1 = 0 for i in 0...100{ sum1 += i } print (sum1) for i in (10...100).reverse(){ sum1 /= i } print(sum1) 

Puede considerar usar C-Style while loop en su lugar. Esto funciona bien en Swift 3:

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

Puede usar el método reverse () para valores reversibles fáciles.

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

El método reverse () invierte los valores.