mac - Swift 3 para bucle con incremento
swift language (4)
Swift 2.2 -> 3.0:
Strideable
: s
stride(...)
reemplazado por funciones de
stride(...)
global
stride(...)
En Swift 2.2, podemos (como lo ha intentado en su propio intento) hacer uso de las funciones
Strideable
(e implementadas por defecto)
stride(through:by:)
y
stride(to:by:)
del protocolo
Strideable
/* Swift 2.2: stride example usage */ let from = 0 let to = 10 let through = 10 let by = 1 for _ in from.stride(through, by: by) { } // from ... through (steps: ''by'') for _ in from.stride(to, by: by) { } // from ..< to (steps: ''by'')
Mientras que en Swift 3.0, estas dos funciones se han eliminado de
Strideable
en favor de
las funciones globales
stride(from:through:by:)
y
stride(from:to:by:)
;
por lo tanto, la versión equivalente Swift 3.0 de lo anterior sigue como
/* Swift 3.0: stride example usage */ let from = 0 let to = 10 let through = 10 let by = 1 for _ in stride(from: from, through: through, by: by) { } for _ in stride(from: from, to: to, by: by) { }
En su ejemplo, desea usar la zancada alternativa de intervalo cerrado
stride(from:through:by:)
, ya que el invariante en su bucle
for
utiliza una comparación menor
o igual a
(
<=
).
Es decir
/* example values of your parameters ''first'', ''last'' and ''interval'' */
let first = 0
let last = 10
let interval = 2
var n = 0
for f in stride(from: first, through: last, by: interval) {
print(f)
n += 1
} // 0 2 4 6 8 10
print(n) // 6
Donde, naturalmente, usamos su bucle
for
solo como un ejemplo del paso de bucle
for
a
stride
, como puede, naturalmente, para su ejemplo específico, simplemente calcule
n
sin la necesidad de un bucle (
n=1+(last-first)/interval
).
Swift 3.0: una alternativa al
stride
para una lógica de incremento iterativo más compleja
Con
la implementación de la propuesta de evolución SE-0094
, Swift 3.0 introdujo las funciones de
sequence
global:
que puede ser una alternativa apropiada para
stride
en casos con una relación de incremento iterativo más compleja (que no es el caso en este ejemplo).
Declaración (es)
func sequence<T>(first: T, next: @escaping (T) -> T?) -> UnfoldSequence<T, (T?, Bool)> func sequence<T, State>(state: State, next: @escaping (inout State) -> T?) -> UnfoldSequence<T, State>
Veremos brevemente la primera de estas dos funciones.
Los
next
argumentos tienen un cierre que aplica cierta lógica para construir perezosamente el siguiente elemento de secuencia dado el actual (comenzando por el
first
).
La secuencia finaliza cuando
next
devuelve
nil
, o infinite, si
next
no devuelve
nil
.
Aplicado al sencillo ejemplo de paso constante anterior, el método de
sequence
es un poco detallado y exagerado con la solución de
stride
adecuada para este propósito:
let first = 0
let last = 10
let interval = 2
var n = 0
for f in sequence(first: first,
next: { $0 + interval <= last ? $0 + interval : nil }) {
print(f)
n += 1
} // 0 2 4 6 8 10
print(n) // 6
Sin embargo, las funciones de
sequence
vuelven muy útiles para casos con zancadas no constantes, por ejemplo, como en el ejemplo cubierto en las siguientes preguntas y respuestas:
Solo tenga cuidado de terminar la secuencia con un eventual retorno
nil
(si no: generación de elementos "infinitos"), o, cuando llegue Swift 3.1, utilice su generación perezosa en combinación con el método de
prefix(while:)
para secuencias, como descrito en la propuesta de evolución
SE-0045
.
La última aplicada al ejemplo de ejecución de esta respuesta hace que el enfoque de
sequence
menos detallado, incluyendo claramente los criterios de terminación de la generación del elemento.
/* for Swift 3.1 */
// ... as above
for f in sequence(first: first, next: { $0 + interval })
.prefix(while: { $0 <= last }) {
print(f)
n += 1
} // 0 2 4 6 8 10
print(n) // 6
¿Cómo escribo lo siguiente en Swift3?
for (f = first; f <= last; f += interval)
{
n += 1
}
Este es mi propio intento
for _ in 0.stride(to: last, by: interval)
{
n += 1
}
Con Swift 5, puede elegir uno de los 5 ejemplos siguientes para resolver su problema.
# 1
Uso de la función
stride(from:to:by:)
let first = 0
let last = 10
let interval = 2
let sequence = stride(from: first, to: last, by: interval)
for element in sequence {
print(element)
}
/*
prints:
0
2
4
6
8
*/
# 2
Uso de la
sequence(first:next:)
función
let first = 0
let last = 10
let interval = 2
let unfoldSequence = sequence(first: first, next: {
$0 + interval < last ? $0 + interval : nil
})
for element in unfoldSequence {
print(element)
}
/*
prints:
0
2
4
6
8
*/
# 3
Usar el
init(_:)
AnySequence
init(_:)
let anySequence = AnySequence<Int>({ () -> AnyIterator<Int> in
let first = 0
let last = 10
let interval = 2
var value = first
return AnyIterator<Int> {
defer { value += interval }
return value < last ? value : nil
}
})
for element in anySequence {
print(element)
}
/*
prints:
0
2
4
6
8
*/
# 4.
Usando el método
CountableRange
filter(_:)
let first = 0
let last = 10
let interval = 2
let range = first ..< last
let lazyCollection = range.lazy.filter({ $0 % interval == 0 })
for element in lazyCollection {
print(element)
}
/*
prints:
0
2
4
6
8
*/
# 5.
Usando el método
flatMap(_:)
let first = 0
let last = 10
let interval = 2
let range = first ..< last
let lazyCollection = range.lazy.compactMap({ $0 % interval == 0 ? $0 : nil })
for element in lazyCollection {
print(element)
}
/*
prints:
0
2
4
6
8
*/
Simplemente, código de trabajo para Swift 3.0:
let (first, last, interval) = (0, 100, 1)
var n = 0
for _ in stride(from: first, to: last, by: interval) {
n += 1
}
para _ en 0. deslizamiento (hasta: último, por: intervalo) {n + = 1}