Reemplazo del lazo estilo C en Swift 2.2

Swift 2.2 dejó de usar el bucle C-style. Sin embargo, en algunos casos, el nuevo operador de rango simplemente no funciona igual.

for var i = 0; i < -1; ++i { ... } 

y

 for i in 0..<-1 { ... } 

El último fallará en el tiempo de ejecución. Puedo envolver el ciclo con un if , pero está un poco desordenado. Algunas veces este tipo de bucle es útil.

¿Alguna idea?

Casos de uso

  1. Debe enumerar todos los elementos de una matriz, excepto la última.
  2. Necesita enumerar todos los números enteros enteros en un rango decimal, pero el rango puede ser como [0.5, 0.9] y por lo tanto no hay números enteros (después de algunas matemáticas), lo que da como resultado un bucle vacío.

Aunque no es tan “bonita”, puedes usar stride :

 for var i in 0.stride(to: -1, by: -1) { print(i) } 

Imitar el “ciclo estilo C”

No del todo bonito, pero puede ajustar el límite superior del rango con un max(0, ..) para asegurarse de que nunca toma valores negativos.

 let foo : [Int] = [] for i in 0.. 

Preferiría, sin embargo, la from.stride(to:by) (que ya se ha mencionado en las otras respuestas, véase, por ejemplo, la respuesta de Michael).

Creo que es valioso señalar explícitamente, sin embargo, que from.stride(to:by) devuelve claramente un StrideTo vacío (o, si se convierte a una matriz: una matriz vacía) si intenta pasar a un número que es menor que de pero con un paso positivo. Por ejemplo, caminar de 0 a -42 por 1 no intentará avanzar todo el camino a través de "∞ -> -∞ -> -42" (es decir, un caso de error), sino que simplemente devuelve un StrideTo vacío (como debería):

 Array(0.stride(to: -42, by: 1)) // [] // -> equivalent to your C loop: for i in 0.stride(to: foo.count-1, by: 1) { print(i) } 

Caso de uso 1: enumerar todos menos el último elemento de una matriz

Para este caso de uso específico, una solución simple es usar dropLast() (como describe Sulthan en los comentarios a su pregunta) seguido de forEach .

 let foo = Array(1...5) foo.dropLast().forEach { print($0) } // 1 2 3 4 

O bien, si necesita más control sobre qué abandonar, aplique un filtro a su matriz

 let foo = Array(1...5) foo.filter { $0 < foo.count }.forEach { print($0) } // 1 2 3 4 

Caso de uso 2: enumerar todos los enteros en un rango decimal, lo que permite que esta enumeración esté vacía

Para su ejemplo de intervalo decimal / doble cerrado ( [0.6, 0.9] ; un intervalo en lugar de un rango en el contexto de la syntax Swift), puede convertir el intervalo cerrado a un rango entero (usando la función forEach ) y aplicar un forEach sobre el último

 let foo : (ClosedInterval) -> () = { (Int(ceil($0.start)).. 

O bien, si desea enumerar específicamente los enteros (posibles) contenidos en este intervalo; use como extensión adaptada a su propósito:

 protocol MyDoubleBounds { func ceilToInt() -> Int } extension Double: MyDoubleBounds { func ceilToInt() -> Int { return Int(ceil(self)) // no integer bounds check in this simple example } } extension ClosedInterval where Bound: MyDoubleBounds { func enumerateIntegers() -> EnumerateSequence<(Range)> { return (self.start.ceilToInt() ..< self.end.ceilToInt()) .enumerate() } } 

Ejemplo de uso:

 for (i, intVal) in (1.3...3.2).enumerateIntegers() { print(i, intVal) } /* 0 2 1 3 */ for (i, intVal) in (0.6...0.9).enumerateIntegers() { print(i, intVal) } /* nothing */ 

Como referencia: En swift 3.0 stride ahora se define globalmente, lo que hace que el loop se vea más natural:

 for i in stride(from: 10, to: 0, by: -1){ print(i) } /* 10 9 8 7 6 5 4 3 2 1 */ 

Para Swift 3 y necesita cambiar el “índice”

 for var index in stride(from: 0, to: 10, by: 1){}