Обратный диапазон в Swift
Есть ли способ работать с реверсивными диапазонами в Swift?
Например:
for i in 5...1 {
// do something
}
- бесконечный цикл.
Я знаю, что вместо 1..5
можно использовать 1..5
, вычислить j = 6 - i
и использовать j
в качестве моего индекса. Мне просто интересно, есть ли что-нибудь более разборчивое?
Ответы
Ответ 1
Обновление Для последней версии 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 я 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 reverse(1...5) { println(i) } // prints 5,4,3,2,1
В сообщении 0x7fffffff есть новая конструкция шага, которую можно использовать для итерации и приращения произвольными целыми числами. Apple также заявила, что поддержка с плавающей запятой идет.
Источник из его ответа:
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
}
Ответ 2
Есть что-то тревожное в асимметрии этого:
for i in (1..<5).reverse()
... в отличие от этого:
for i in 1..<5 {
Это означает, что каждый раз, когда я хочу сделать обратный диапазон, я должен помнить, чтобы поставить круглые скобки, плюс я должен написать .reverse()
в конце, торчащий, как больной большой палец. Это действительно некрасиво по сравнению с C-стилем для циклов, которые симметрично считают вверх и вниз. Так что вместо этого я использовал C-стиль для циклов. Но в Swift 2.2 циклы в стиле C исчезают! Так что мне пришлось поторопиться с заменой всех моих .reverse()
циклов в стиле 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 (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()
}
Версия Swift 5 (Xcode 10.2.1):
infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound)
-> ReversedCollection<Range<Bound>>
where Bound : Strideable {
return (minimum..<maximum).reversed()
}
Ответ 3
Похоже, что ответы на этот вопрос немного изменились по мере продвижения по бета-версиям. Начиная с бета-версии 4, из языка были удалены как функция by()
, так и тип 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
}
Обратите внимание, что я также включил в этот пост нового оператора эксклюзивного диапазона. ..
был заменен на ..<
.
Изменить: Из примечаний к выпуску Xcode 6 beta 5 Apple добавила следующее предложение для этого:
ReverseRange удален; использовать ленивый (х..
Вот пример.
for i in lazy(0...5).reverse() {
// 0, 1, 2, 3, 4, 5
}
Ответ 4
Xcode 7, beta 2:
for i in (1...5).reverse() {
// do something
}
Ответ 5
Swift 3, 4+: вы можете сделать это так:
for i in sequence(first: 10, next: {$0 - 1}) {
guard i >= 0 else {
break
}
print(i)
}
результат: 10, 9, 8... 0
Вы можете настроить его так, как вам нравится. Для получения дополнительной информации прочитайте func sequence<T>
reference
Ответ 6
Это может быть другим способом сделать это.
(1...5).reversed().forEach { print($0) }
Ответ 7
Функция Reverse() используется для обратного числа.
Var n: Int//Введите номер
Для я в 1... n.reverse() {Print (i)}