Обратный ассортимент в Swift
есть ли способ работать с обратными диапазонами в Swift?
например:
for i in 5...1 {
// do something
}
бесконечный цикл.
Я знаю, что могу использовать 1..5
вместо расчета j = 6 - i
и использовать j
как мой индекс. Мне просто интересно, есть ли что-нибудь более разборчивое?
7 ответов:
обновление для последнего Swift 3 (все еще работает в Swift 4)
можно использовать
reversed()
метод на диапазонеfor i in (1...5).reversed() { print(i) } // 5 4 3 2 1
или
stride(from:through:by:)
методfor i in stride(from:5,through:1,by:-1) { print(i) } // 5 4 3 2 1
stide(from:to:by:)
аналогично, но исключает последнее значениеfor i in stride(from:5,to:0,by:-1) { print(i) } // 5 4 3 2 1
обновление для последнего Swift 2
прежде всего, расширения протокола меняются как
reverse
используется:
for i in (1...5).reverse() { print(i) } // 5 4 3 2 1
Stride был переработан в Xcode 7 Beta 6. Новое использование:
for i in 0.stride(to: -8, by: -2) { print(i) } // 0 -2 -4 -6 for i in 0.stride(through: -8, by: -2) { print(i) } // 0 -2 -4 -6 -8
он также работает для
Doubles
:for i in 0.5.stride(to:-0.1, by: -0.1) { print(i) }
будьте осторожны с плавающей точкой сравнивает здесь для границ.
ранее редактировать для Swift 1.2: начиная с Xcode 6 Beta 4, by и ReverseRange больше не существует :[
если вы просто хотите изменить диапазон,реверс
есть что-то тревожное в асимметрии этого:
for i in (1..<5).reverse()
...в противоположность этому:
for i in 1..<5 {
это означает, что каждый раз, когда я хочу сделать обратный диапазон, я должен помнить, чтобы поставить скобки, плюс я должен написать, что
.reverse()
на конце, торчит, как больной палец. Это действительно уродливо по сравнению с C-стилем для петель, которые симметричны, считая вверх и отсчитывая вниз. Поэтому я, как правило, использовал C-стиль для циклов вместо этого. Но в Swift 2.2, C-стиль для петель уходит! Так что мне приходилось бегать вокруг, заменяя все мое уменьшение с-стиль петли с этой уродливой.reverse()
построить-интересно все время, почему на земле нет оператора обратного диапазона?но подождите! Это Swift - нам разрешено определять наших собственных операторов!! Здесь мы идем:
infix operator >>> { associativity none precedence 135 } func >>> <Pos : ForwardIndexType where Pos : Comparable>(end:Pos, start:Pos) -> ReverseRandomAccessCollection<(Range<Pos>)> { return (start..<end).reverse() }
так что теперь я могу сказать:
for i in 5>>>1 {print(i)} // 4, 3, 2, 1
это охватывает только самый распространенный случай, который происходит в моем коде, но это и самый распространенный случай, так что это все, что мне нужно на данный момент.
у меня был какой-то внутренний кризис, связанный с оператором. Я бы хотел использовать
>..
, как реверс..<
, но это не законно: вы не можете использовать точку после номера-точка, кажется. Я считал..>
но решил, что это слишком трудно отличить от..<
. Хорошая вещь о>>>
это он кричит на тебя:"вниз к!"( Конечно, вы можете придумать другой оператор. Но мой совет: для супер симметрии определите<<<
что делать..<
делает, и теперь у вас есть<<<
и>>>
которые симметричны и просты в вводе.)
Swift 3 version (Xcode 8 seed 6):
infix operator >>> : RangeFormationPrecedence func >>><Bound>(maximum: Bound, minimum: Bound) -> ReversedRandomAccessCollection<CountableRange<Bound>> where Bound : Comparable, Bound.Stride : Integer { return (minimum..<maximum).reversed() }
версия Swift 4 (Xcode 9 beta 3):
infix operator >>> : RangeFormationPrecedence func >>><Bound>(maximum: Bound, minimum: Bound) -> ReversedRandomAccessCollection<CountableRange<Bound>> where Bound : Comparable & Strideable { return (minimum..<maximum).reversed() }
версия Swift 4.2 (Xcode 10 beta 1):
infix operator >>> : RangeFormationPrecedence func >>><Bound>(maximum: Bound, minimum: Bound) -> ReversedRandomAccessCollection<Range<Bound>> where Bound : Strideable { return (minimum..<maximum).reversed() }
похоже, что ответы на этот вопрос немного изменились по мере того, как мы продвигались через бета. По состоянию на бета 4, оба и
ReversedRange
тип был удален из языка. Если вы хотите сделать обратный диапазон, ваши варианты теперь следующие:1: Создайте прямой диапазон, а затем используйте
reverse()
функция для того чтобы обратить его.for x in reverse(0 ... 4) { println(x) // 4, 3, 2, 1, 0 } for x in reverse(0 ..< 4) { println(x) // 3, 2, 1, 0 }
2: Используйте новый
stride()
функции которые были добавлены в бета-версии 4, который включает в себя функции чтобы указать начальный и конечный индексы, а также количество итераций.for x in stride(from: 0, through: -8, by: -2) { println(x) // 0, -2, -4, -6, -8 } for x in stride(from: 6, to: -2, by: -4) { println(x) // 6, 2 }
обратите внимание, что я также включил новый оператор эксклюзивного диапазона в этот пост.
..
был заменен..<
.Edit: из Xcode 6 бета 5 примечания к выпуску, Apple добавила следующее предложение для обработки этого:
ReverseRange был удален; используйте lazy(x..
вот образец.
for i in lazy(0...5).reverse() { // 0, 1, 2, 3, 4, 5 }
Swift 3, 4+: вы можете сделать это так:
for i in sequence(first: 10, next: { - 1}) { guard i >= 0 else { break } print(i) }
результат: 10, 9, 8 ... 0
Вы можете настроить его так, как вам нравится. Для получения дополнительной информации читайте
func sequence<T>
ссылка