Ответ 1
Swift 2.2 → 3.0: Strideable
: s stride(...)
заменен глобальными stride(...)
функциями
В Swift 2.2 мы можем (как вы пробовали в своей собственной попытке) использовать голубые (и по умолчанию) функции stride(through:by:)
и stride(to:by:)
из протокола 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')
В то время как в Swift 3.0 эти две функции были удалены из Strideable
в пользу глобальных функций stride(from:through:by:)
и stride(from:to:by:)
; поэтому эквивалентная версия Swift 3.0 выше следует как
/* 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) { }
В вашем примере вы хотите использовать альтернативу с интервалом с интервалом stride(from:through:by:)
, так как инвариант в вашем цикле for
использует сравнение с меньшим или равным (<=
). То есть.
/* 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
Где, естественно, мы используем ваш цикл for
только как пример перехода из цикла for
в stride
, как вы можете, естественно, для вашего конкретного примера просто вычислить n
без необходимости цикл (n=1+(last-first)/interval
).
Swift 3.0: альтернатива stride
для более сложной итерационной логики увеличения
С помощью реализации эволюционного предложения SE-0094 Swift 3.0 представил глобальные функции sequence
:
которая может быть подходящей альтернативой stride
для случаев с более сложным соотношением приращения итерации (что не так в этом примере).
Декларация (ы)
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>
Мы кратко рассмотрим первую из этих двух функций. Аргументы next
принимают замыкание, которое применяет некоторую логику для ленивого построения следующего элемента последовательности с учетом текущего (начиная с first
). Последовательность завершается, когда next
возвращает nil
или бесконечно, если a next
никогда не возвращает nil
.
Применительно к приведенному выше примеру с простой степенью, метод sequence
является немного подробным и overkill w.r.t. решение stride
для решения этой задачи:
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
Функции sequence
становятся очень полезными для случаев с непостоянным шагом, однако, например, как в примере, приведенном в следующем Q & A:
Просто позаботьтесь о завершении последовательности с последующим возвратом элемента nil
(если нет: "бесконечный" ), или, когда Swift 3.1 прибывает, используйте свое ленивое поколение в сочетании с методом prefix(while:)
для последовательности, как описано в эволюционном предложении SE-0045. Последнее применительно к текущему примеру этого ответа делает подход sequence
менее подробным, в том числе критерии завершения генерации элемента.
/* 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