¿Hay alguna forma de trabajar con rangos inversos en Swift?
Por ejemplo:
for i in 5...1 {
// do something
}
es un bucle infinito.
En las versiones más recientes de Swift, ese código se compila, pero en tiempo de ejecución da el error:
Error fatal: no se puede formar el rango con upperBound <lowerBound
Sé que puedo usar 1..5
en su lugar, calcular j = 6 - i
y usar j
como mi índice. Me preguntaba si había algo más legible.
Respuestas:
Actualización para el último Swift 3 (todavía funciona en Swift 4)
Puedes usar el
reversed()
método en un rangoO
stride(from:through:by:)
métodostide(from:to:by:)
es similar pero excluye el último valorActualización para el último Swift 2
En primer lugar, las extensiones de protocolo cambian cómo
reverse
se usa:for i in (1...5).reverse() { print(i) } // 5 4 3 2 1
Stride ha sido reelaborado en Xcode 7 Beta 6. El nuevo uso es:
También funciona para
Doubles
:Tenga cuidado con las comparaciones de punto flotante aquí para los límites.
Edición anterior para Swift 1.2 : A partir de Xcode 6 Beta 4, by y ReverseRange ya no existen: [
Si solo está buscando invertir un rango, la función inversa es todo lo que necesita:
Según lo publicado por 0x7fffffff, hay una nueva construcción de zancada que se puede usar para iterar e incrementar en números enteros arbitrarios. Apple también declaró que llegará el soporte de punto flotante.
Procedente de su respuesta:
fuente
(1...5).reverse()
(como una llamada de función), actualice su respuesta. (Como solo tiene dos caracteres, no pude editar tu publicación).(1...5).reversed()
. Además, el ejemplo de.stride()
no funciona y necesita la función gratuita en sustride(from:to:by:)
lugar.stride
código para swift 3 es ligeramente incorrecto. para incluir el número 1, necesitaría usarthrough
opuesto ato
esto:for i in stride(from:5,through:1,by:-1) { print(i) }
reversed
tiene una complejidad de O (1) porque simplemente envuelve la colección original y no requiere una iteración para construirla.Hay algo preocupante sobre la asimetría de esto:
... en contraposición a esto:
Significa que cada vez que quiero hacer un rango inverso, tengo que recordar poner el paréntesis, además tengo que escribir eso
.reverse()
al final, sobresaliendo como un pulgar dolorido. Esto es realmente feo en comparación con los bucles for de estilo C, que son simétricos contando hacia arriba y hacia abajo. Así que tendía a usar el estilo C para bucles. ¡Pero en Swift 2.2, los bucles for estilo C desaparecerán! Así que tuve que apresurarme reemplazando todos mis bucles for decrecientes de estilo C con esta fea.reverse()
construcción, preguntándome todo el tiempo, ¿por qué diablos no hay un operador de rango inverso?¡Pero espera! Esto es Swift, ¡¡tenemos permitido definir nuestros propios operadores !! Aquí vamos:
Así que ahora puedo decir:
Esto cubre solo el caso más común que ocurre en mi código, pero es de lejos el caso más común, por lo que es todo lo que necesito en este momento.
Tuve una especie de crisis interna con el operador. Me hubiera gustado usar
>..
, como lo contrario de..<
, pero eso no es legal: no se puede usar un punto después de un no punto, parece. Lo consideré,..>
pero decidí que era demasiado difícil distinguirlo..<
. Lo bueno de>>>
es que te grita: " abajo a!" (Por supuesto, puede pensar en otro operador. Pero mi consejo es: para la super simetría, defina<<<
para hacer lo que..<
hace, y ahora tiene<<<
y>>>
cuáles son simétricos y fáciles de escribir).Versión Swift 3 (Xcode 8 seed 6):
Versión Swift 4 (Xcode 9 beta 3):
Versión Swift 4.2 (Xcode 10 beta 1):
Versión Swift 5 (Xcode 10.2.1):
fuente
>>>
operador es realmente genial! Espero que los diseñadores de Swift presten atención a cosas como esa, porque quedarsereverse()
al final de las expresiones entre paréntesis se siente raro. No hay ninguna razón por la que no puedan manejar los5>..0
rangos automáticamente, porque elForwardIndexType
protocolo proporciona undistanceTo()
operador perfectamente razonable que puede usarse para determinar si el paso debe ser positivo o negativo.Parece que las respuestas a esta pregunta han cambiado un poco a medida que avanzamos en las betas. A partir de la beta 4, tanto la
by()
función como elReversedRange
tipo se han eliminado del lenguaje. Si está buscando hacer un rango inverso, sus opciones ahora son las siguientes:1: Cree un rango de avance y luego use la
reverse()
función para revertirlo.2: Utilice las nuevas
stride()
funciones que se agregaron en la versión beta 4, que incluye funciones para especificar los índices de inicio y finalización, así como la cantidad de iteración.Tenga en cuenta que también he incluido el nuevo operador de rango exclusivo en esta publicación.
..
fue reemplazado por..<
.Editar: De las notas de la versión de Xcode 6 beta 5 , Apple agregó la siguiente sugerencia para manejar esto:
He aquí un ejemplo.
fuente
lazy(0....5).reverse()
y no veo las notas de la versión beta 5. ¿Conoce otras discusiones sobre este tema? Además, para su información, los números dentro de esefor
bucle están al revés en su ejemplo.// 0, 1, 2, 3, 4, 5
pero en realidad debería invertirse. El comentario es engañoso.Xcode 7, beta 2:
fuente
Swift 3, 4+ : puedes hacerlo así:
resultado : 10, 9, 8 ... 0
Puedes personalizarlo como quieras. Para más información lea la
func sequence<T>
referenciafuente
Esta podría ser otra forma de hacer esto.
fuente
La función Reverse () se utiliza para el número inverso.
Var n: Int // Ingrese el número
Para i en 1 ... n.reverse () {Imprimir (i)}
fuente