ios - the - Reemplazo para el bucle de estilo C en Swift 2.2
the swift programming language pdf (4)
Swift 2.2 desaprobó el bucle de estilo C. 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 { ... }
La última fallará en tiempo de ejecución.
Puedo envolver el bucle con un
if
, pero está un poco desordenado.
A veces este tipo de bucle es útil.
¿Alguna idea?
Casos de uso
- Debe enumerar todos los elementos de una matriz, excepto el último.
- Debe 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 enteros (después de algunas matemáticas), lo que da como resultado un bucle vacío.
Imitando el "bucle de estilo C"
No del todo bonito, pero puede ajustar el rango: s límite superior con un
max(0, ..)
para asegurarse de que nunca tome valores negativos.
let foo : [Int] = []
for i in 0..<max(0,foo.count-1) {
print(i)
}
Sin embargo,
from.stride(to:by)
la
from.stride(to:by)
(que ya se ha mencionado en las otras respuestas, ver, por ejemplo, la respuesta de Michael).
Sin embargo, creo que es valioso señalar explícitamente que
from.stride(to:by)
devuelve perfectamente un
StrideTo
vacío (o, si se convierte en una matriz: una matriz vacía) si intenta avanzar
a
un número menor que pero
por
un paso positivo.
Por ejemplo, avanzar de
0
a
-42
por
1
no intentará avanzar completamente 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: enumere todos menos el último elemento de una matriz
Para este caso de uso específico, una solución simple es usar
dropLast()
(como lo 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, 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: enumere todos los enteros en un rango decimal, permitiendo que esta enumeración esté vacía
Para su ejemplo de
intervalo
decimal / doble
intervalo cerrado
(
[0.6, 0.9]
; un intervalo en lugar de un rango en el contexto de la sintaxis Swift), puede convertir el intervalo cerrado en un rango entero (usando la función
forEach
) y aplicar un
forEach
sobre el último
let foo : (ClosedInterval<Double>) -> () = {
(Int(ceil($0.start))..<Int(ceil($0.end)))
.forEach { print($0) }
}
foo(0.5...1.9) // 1
foo(0.5...0.9) // nothing
O, si desea enumerar específicamente los (posibles) enteros contenidos en este intervalo; utilícelo como extensión adecuada para 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<Int>)> {
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 */
Aunque no es tan "bonito", puedes usar
stride
:
for var i in 0.stride(to: -1, by: -1) {
print(i)
}
Como referencia: en Swift 3.0, la zancada ahora se define globalmente, lo que hace que el bucle 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){}