Swift 3 para bucle con incremento

¿Cómo escribo lo siguiente en Swift3?

for (f = first; f <= last; f += interval) { n += 1 } 

Este es mi propio bash

 for _ in 0.stride(to: last, by: interval) { n += 1 } 

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 bash) hacer uso de las funciones stride(through:by:) y ejecutadas 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 han sido eliminadas de Strideable en favor de la función global stride(from:through:by:) stride(from:to:by:) ; por lo tanto, la versión equivalente de 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 utilizar la zancada alternativa de stride(from:through:by:) intervalo cerrado stride(from:through:by:) , ya que la invariante en su bucle for usa la comparación en menos 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 for loop to stride , como puede naturalmente, para su ejemplo específico, simplemente calcular n sin la necesidad de un bucle ( n=1+(last-first)/interval ).

Swift 3.0: una alternativa a la stride para una lógica de incremento de iteración más compleja

Con la implementación de la propuesta de evolución SE-0094 , Swift 3.0 introdujo las funciones de sequence globales:

  • sequence(first:next:) ,
  • sequence(state:next:) ,

que puede ser una alternativa apropiada para stride en casos con una relación de incremento de iteración más compleja (que no es el caso en este ejemplo).

Declaración (es)

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

Veremos brevemente la primera de estas dos funciones. Los next argumentos tienen un cierre que aplica cierta lógica para construir lentamente el siguiente elemento de secuencia dado el actual (empezando por el first ). La secuencia se termina cuando el next devuelve nil , o infinite, si el next nunca devuelve nil .

Aplicado al simple ejemplo de paso constante constante, 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:

  • Express para bucles en rápido con rango dynamic

Simplemente tenga cuidado de terminar la secuencia con un eventual retorno nil (si no: generación de elementos "infinitos") o, cuando llegue Swift 3.1, haga uso de 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 . El último aplicado al ejemplo de ejecución de esta respuesta hace que el enfoque de la 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 

Con Swift 3 y Swift 4, puede elegir uno de los 5 siguientes ejemplos 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 { // do stuff print(element) } /* prints: 0 2 4 6 8 */ 

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

 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 { // do stuff print(element) } /* prints: 0 2 4 6 8 */ 

# 3. Uso del AnySequence init(_:) AnySequence init(_:)

 let anySequence = AnySequence({ () -> AnyIterator in let first = 0 let last = 10 let interval = 2 var value = first return AnyIterator { defer { value += interval } return value < last ? value : nil } }) for element in anySequence { // do stuff print(element) } /* prints: 0 2 4 6 8 */ 

# 4. Usando el método de filter(_:) 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 { // do stuff 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.flatMap({ $0 % interval == 0 ? $0 : nil }) for element in lazyCollection { // do stuff 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.stride (hasta: last, by: interval) {n + = 1}