2016-10-16 1 views
2

... или как я могу использовать индекс внутри для условия циклаЭкспресс для петель в стриже с динамическим диапазоном

Эй люди Поскольку мы остались без гр стиля для петель в быстрых 3 я могу» t, похоже, найти способ выразить немного сложнее для циклов, так что, возможно, вы можете мне помочь.

Если бы я писал этот

for(int i=5; num/i > 0; i*=5) 

в быстром 3, как бы мне это сделать?

Замкнутая я пришел был:

for i in stride(from: 5, through: num, by: 5) where num/i > 0 

, но это, конечно, итерация 5 кусков в то время, вместо того, чтобы, если я будучи: 5, 25, 125 и т.д.

Есть идеи?

Благодаря

+1

Если мы говорим о целых числах, это не 'num/i> 0' то же самое, что и запись' num> i'? – Sulthan

+0

@Sulthan Нет, рассмотрим 'num = 5' &' i = 5', а также 'num = 5' &' i = -5' – Hamish

+0

плюс вам все равно придется использовать i в условии цикла for – alex

ответ

4

Используя вспомогательную функцию (первоначально определенный в Converting a C-style for loop that uses division for the step to Swift 3)

public func sequence<T>(first: T, while condition: @escaping (T)-> Bool, next: @escaping (T) -> T) -> UnfoldSequence<T, T> { 
    let nextState = { (state: inout T) -> T? in 
     // Return `nil` if condition is no longer satisfied: 
     guard condition(state) else { return nil } 
     // Update current value _after_ returning from this call: 
     defer { state = next(state) } 
     // Return current value: 
     return state 
    } 
    return sequence(state: first, next: nextState) 
} 

вы можете написать цикл, как

let num = 1000 
for i in sequence(first: 5, while: { num/$0 > 0 }, next: { $0 * 5 }) { 
    print(i) 
} 

Более простое решение было бы в то время как петля:

var i = 5 
while num/i > 0 { 
    print(i) 
    i *= 5 
} 

, но преимуществом первого решения является то, что область действия переменной цикла ограничена телом цикла и что переменная цикла является константой.

Swift 3.1 обеспечит prefix(while:) method for sequences, , а затем вспомогательная функция больше не является необходимой:

let num = 1000 
for i in sequence(first: 5, next: { $0 * 5 }).prefix(while: { num/$0 > 0 }) { 
    print(i) 
} 

Все выше решений является «эквивалентен» данным циклом C. Тем не менее, все они могут погибнуть, если num находится недалеко от Int.max и $0 * 5 переполнение. Если это проблема, вы должны проверить , если $0 * 5 подходит для целочисленного диапазона до, выполняющего умножение.

На самом деле, что делает цикл проще - по крайней мере, если мы предположим, что num >= 5 так, что цикл выполняется по крайней мере один раз:

for i in sequence(first: 5, next: { $0 <= num/5 ? $0 * 5 : nil }) { 
    print(i) 
} 
+0

Как ужасно альтернативный (ужасно даже игнорируя отсутствие проверок ограничений «Double» to 'Int') до функции справки выше, до Swift 3.1, можно также использовать' sequence (first: 5, next: {$ 0 * 5}). prefix (Int (log (Двойной (num))/log (5)));;) – dfri

+0

@dfri: ... и возможные ошибки округления. - Я действительно думаю, что предстоящий 'префикс (while:)' и 'drop (while:)' решит эту и подобные проблемы красиво. –

+0

Действительно. Шутки в сторону, 'sequence (first: 5, next: {num/$ 0> 0? $ 0 * 5: nil}). DropLast()' должен быть допустимой альтернативой, используя 'Optional'-return' next 'замыкание в' последовательности (первая: T, следующая: T -> T?) '. – dfri

1

Для полноты: альтернатива подхода петлевой while использует в AnyIterator :

let num = 1000 

var i = 5 
for i in AnyIterator<Int>({ 
    return i <= num ? { defer { i *= 5 }; return i }() : nil 
}) { 
    // note that we choose to shadow the external i variable name, 
    // such that any access to i within this loop will only refer 
    // to the loop local immutable variable i. 
    print(i) 

    // e.g. i += 1 not legal, i refers to a constant here! 

} /* 5 
    25 
    125 
    625 */ 

Этот метод страдает тем же недостатком, как while петли в том, что цикл «внешнего» i переменная сохраняется вне и после области цикла.Однако эта внешняя переменная i не является переменной i, доступной внутри тела цикла, поскольку мы позволяем теневой переменной цикла i затушевывать внешний, ограничивая доступ к i внутри тела неизменному, временному (область действия по локальной сети) один.

+0

Обратите внимание, что это слишком часто обновляет переменную цикла (т. Е. Даже при возврате 'nil'). Это может привести к переполнению целых чисел в этом приложении и может быть проблематичным в других случаях использования (например, обход связанного списка). –

+0

@MartinR Ах, да, я заметил дополнительное увеличение моего ответа, но я не осознавал возможных опасностей, которые он причастен. Обновлен версией, по крайней мере аналогичной циклу while, w.r.t. значение внешнего завершения цикла «i». Благодаря! – dfri

 Смежные вопросы

  • Нет связанных вопросов^_^