Обратный диапазон в 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)}