Как перебирать цикл в обратном порядке в swift?

Когда я использую цикл for в Playground, все работает нормально, пока я не изменил первый параметр цикла for на максимальное значение. (итерируется в порядке убывания)

Это ошибка? У кого-нибудь еще есть?

for index in 510..509
{
    var a = 10
}

Счетчик, отображающий количество итераций, которые будут выполняться, продолжает тикать...

enter image description here

Ответ 1

Xcode 6 beta 4 добавил две функции для итерации по диапазонам с шагом, отличным от одного: stride(from: to: by:), который используется с эксклюзивными диапазонами и stride(from: through: by:), который используется с включенными диапазонами.

Для итерации по диапазону в обратном порядке их можно использовать как показано ниже:

for index in stride(from: 5, to: 1, by: -1) {
    print(index)
}
//prints 5, 4, 3, 2

for index in stride(from: 5, through: 1, by: -1) {
    print(index)
}
//prints 5, 4, 3, 2, 1

Обратите внимание, что ни одна из них не является функцией-членом Range. Они являются глобальными функциями, которые возвращают либо структуру StrideTo, либо StrideThrough, которые определены иначе, чем структура Range.

В предыдущей версии этого ответа использовалась функция члена by() структуры Range, которая была удалена в бета-версии 4. Если вы хотите посмотреть, как это работает, проверьте историю изменений.

Ответ 2

Примените обратную функцию к диапазону для итерации назад:

Для Swift 1.2 и ранее:

// Print 10 through 1
for i in reverse(1...10) {
    println(i)
}

Он также работает с полуоткрытыми диапазонами:

// Print 9 through 1
for i in reverse(1..<10) {
    println(i)
}

Примечание: reverse(1...10) создает массив типа [Int], поэтому, хотя это может быть хорошо для небольших диапазонов, было бы разумно использовать lazy, как показано ниже, или рассмотреть принятый ответ stride, если ваш диапазон большой.


Чтобы избежать создания большого массива, используйте lazy вместе с reverse(). Следующий тест работает эффективно на игровой площадке, показывая, что он не создает массив с одним триллионом Int s!

Тест:

var count = 0
for i in lazy(1...1_000_000_000_000).reverse() {
    if ++count > 5 {
        break
    }
    println(i)
}

Для Swift 2.0 в Xcode 7:

for i in (1...10).reverse() {
    print(i)
}

Обратите внимание, что в Swift 2.0 (1...1_000_000_000_000).reverse() имеет тип ReverseRandomAccessCollection<(Range<Int>)>, поэтому это отлично работает:

var count = 0
for i in (1...1_000_000_000_000).reverse() {
    count += 1
    if count > 5 {
        break
    }
    print(i)
}

Для Swift 3.0 reverse() было переименовано в reversed():

for i in (1...10).reversed() {
    print(i) // prints 10 through 1
}

Ответ 3

Обновлено для Swift 3

Ответ ниже представляет собой сводку доступных опций. Выберите тот, который наилучшим образом соответствует вашим потребностям.

reversed: числа в диапазоне

Вперед

for index in 0..<5 {
    print(index)
}

// 0
// 1
// 2
// 3
// 4

назад

for index in (0..<5).reversed() {
    print(index)
}

// 4
// 3
// 2
// 1
// 0

reversed: элементы в SequenceType

let animals = ["horse", "cow", "camel", "sheep", "goat"]

Вперед

for animal in animals {
    print(animal)
}

// horse
// cow
// camel
// sheep
// goat

назад

for animal in animals.reversed() {
    print(animal)
}

// goat
// sheep
// camel
// cow
// horse

reversed: элементы с индексом

Иногда требуется индекс для итерации по коллекции. Для этого вы можете использовать enumerate(), который возвращает кортеж. Первый элемент кортежа - это индекс, а второй элемент - это объект.

let animals = ["horse", "cow", "camel", "sheep", "goat"]

Вперед

for (index, animal) in animals.enumerated() {
    print("\(index), \(animal)")
}

// 0, horse
// 1, cow
// 2, camel
// 3, sheep
// 4, goat

назад

for (index, animal) in animals.enumerated().reversed()  {
    print("\(index), \(animal)")
}

// 4, goat
// 3, sheep
// 2, camel
// 1, cow
// 0, horse

Обратите внимание, что, как заметил Бен Лахман в своем ответе, вы, вероятно, захотите сделать .enumerated().reversed() а не .reversed().enumerated() (что увеличит число индексов).

шагать: цифры

Stride - это способ итерации без использования диапазона. Есть две формы. Комментарии в конце кода показывают, какой будет версия диапазона (при условии, что размер приращения равен 1).

startIndex.stride(to: endIndex, by: incrementSize)      // startIndex..<endIndex
startIndex.stride(through: endIndex, by: incrementSize) // startIndex...endIndex

Вперед

for index in stride(from: 0, to: 5, by: 1) {
    print(index)
}

// 0
// 1
// 2
// 3
// 4

назад

Изменение размера приращения на -1 позволяет вам вернуться назад.

for index in stride(from: 4, through: 0, by: -1) {
    print(index)
}

// 4
// 3
// 2
// 1
// 0

Обратите внимание, to и through разницу.

шаг: элементы SequenceType

Вперед с шагом 2

let animals = ["horse", "cow", "camel", "sheep", "goat"]

Я использую 2 в этом примере, чтобы показать другую возможность.

for index in stride(from: 0, to: 5, by: 2) {
    print("\(index), \(animals[index])")
}

// 0, horse
// 2, camel
// 4, goat

назад

for index in stride(from: 4, through: 0, by: -1) {
    print("\(index), \(animals[index])")
}

// 4, goat
// 3, sheep 
// 2, camel
// 1, cow  
// 0, horse 

Заметки

Ответ 4

Swift 4 вперед

for i in stride(from: 5, to: 0, by: -1) {
    print(i)
}
//prints 5, 4, 3, 2, 1

for i in stride(from: 5, through: 0, by: -1) {
    print(i)
}
//prints 5, 4, 3, 2, 1, 0

Ответ 5

Для Swift 2.0 и выше вы должны применить обратное к коллекции диапазона

for i in (0 ..< 10).reverse() {
  // process
}

Он был переименован в .reversed() в Swift 3.0

Ответ 6

С помощью Swift 5 вы можете выбрать один из четырех приведенных ниже примеров кода игровой площадки, чтобы решить вашу проблему.


# 1. Использование метода ClosedRange reversed()

ClosedRange имеет метод с именем reversed(). Метод reversed() имеет следующее объявление:

func reversed() -> ReversedCollection<ClosedRange<Bound>>

Возвращает представление, представляющее элементы коллекции в обратном порядке.

Использование:

let reversedCollection = (0 ... 5).reversed()

for index in reversedCollection {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

В качестве альтернативы вы можете использовать метод Range reversed() :

let reversedCollection = (0 ..< 6).reversed()

for index in reversedCollection {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

# 2. Использование функции sequence(first:next:)

Стандартная библиотека Swift предоставляет функцию под названием sequence(first:next:). sequence(first:next:) имеет следующую декларацию:

func sequence<T>(first: T, next: @escaping (T) -> T?) -> UnfoldFirstSequence<T>

Возвращает последовательность, сформированную из first и повторяющихся отложенных приложений next.

Использование:

let unfoldSequence = sequence(first: 5, next: {
    $0 > 0 ? $0 - 1 : nil
})

for index in unfoldSequence {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

# 3. Использование функции stride(from:through:by:)

Стандартная библиотека Swift предоставляет функцию под названием stride(from:through:by:). stride(from:through:by:) имеет следующую декларацию:

func stride<T>(from start: T, through end: T, by stride: T.Stride) -> StrideThrough<T> where T : Strideable

Возвращает последовательность от начального значения к конечному значению и, возможно, включая конечное значение, шагая на указанную величину.

Использование:

let sequence = stride(from: 5, through: 0, by: -1)

for index in sequence {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

В качестве альтернативы вы можете использовать stride(from:to:by:):

let sequence = stride(from: 5, to: -1, by: -1)

for index in sequence {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

# 4. Использование инициализатора AnyIterator init(_:)

AnyIterator имеет инициализатор init(_:). init(_:) имеет следующую декларацию:

init(_ body: @escaping () -> AnyIterator<Element>.Element?)

Создает итератор, который упаковывает данное замыкание в его метод next().

Использование:

var index = 5

guard index >= 0 else { fatalError("index must be positive or equal to zero") }

let iterator = AnyIterator({ () -> Int? in
    defer { index = index - 1 }
    return index >= 0 ? index : nil
})

for index in iterator {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

При необходимости вы можете выполнить рефакторинг предыдущего кода, создав метод расширения для Int и включив в него итератор:

extension Int {

    func iterateDownTo(_ endIndex: Int) -> AnyIterator<Int> {
        var index = self
        guard index >= endIndex else { fatalError("self must be greater than or equal to endIndex") }

        let iterator = AnyIterator { () -> Int? in
            defer { index = index - 1 }
            return index >= endIndex ? index : nil
        }
        return iterator
    }

}

let iterator = 5.iterateDownTo(0)

for index in iterator {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

Ответ 7

В Swift 4 и более поздних

    let count = 50//For example
    for i in (1...count).reversed() {
        print(i)
    }

Ответ 8

Swift 4.0

for i in stride(from: 5, to: 0, by: -1) {
    print(i) // 5,4,3,2,1
}

Если вы хотите включить значение to:

for i in stride(from: 5, through: 0, by: -1) {
    print(i) // 5,4,3,2,1,0
}

Ответ 9

Если требуется выполнить итерацию по массиву (Array или, как правило, любой SequenceType) в обратном порядке. У вас есть несколько дополнительных опций.

Сначала вы можете reverse() массива и пропустить его как обычно. Однако я предпочитаю использовать enumerate() большую часть времени, так как он выводит кортеж, содержащий объект и индекс.

Здесь следует отметить, что важно называть их в правильном порядке:

for (index, element) in array.enumerate().reverse()

дает индексы в порядке убывания (чего я обычно ожидаю). в то время как:

for (index, element) in array.reverse().enumerate() (что ближе к NSArray reverseEnumerator)

перемещает массив назад, но выводит восходящие индексы.

Ответ 10

как для Swift 2.2, Xcode 7.3 (10, июнь 2016):

for (index,number) in (0...10).enumerate() {
    print("index \(index) , number \(number)")
}

for (index,number) in (0...10).reverse().enumerate() {
    print("index \(index) , number \(number)")
}

Выход:

index 0 , number 0
index 1 , number 1
index 2 , number 2
index 3 , number 3
index 4 , number 4
index 5 , number 5
index 6 , number 6
index 7 , number 7
index 8 , number 8
index 9 , number 9
index 10 , number 10


index 0 , number 10
index 1 , number 9
index 2 , number 8
index 3 , number 7
index 4 , number 6
index 5 , number 5
index 6 , number 4
index 7 , number 3
index 8 , number 2
index 9 , number 1
index 10 , number 0

Ответ 11

var sum1 = 0
for i in 0...100{
    sum1 += i
}
print (sum1)

for i in (10...100).reverse(){
    sum1 /= i
}
print(sum1)

Ответ 12

Вместо этого вы можете использовать цикл C-Style while. Это очень хорошо работает в Swift 3:

var i = 5 
while i > 0 { 
    print(i)
    i -= 1
}

Ответ 13

Вы можете использовать метод reversed() для легкого реверсирования значений.

var i:Int
for i in 1..10.reversed() {
    print(i)
}

Метод reversed() переворачивает значения.

Ответ 14

Для этого вы можете использовать петлю while, которая очень проста

var i = 10
while i > 1{
   print(i)
   i = i - 1
}

Но все же, если вы хотите использовать цикл, используйте метод reversed()

for i in (1...10).reversed(){
    print(i)
}

Ответ 15

Вы можете просто сделать это, если у вас есть массив

func reverseArray(a: [Int]) -> [Int] {
   var reverseArr = [Int]()
   for i in stride(from: a.count-1, to: -1, by: -1){
      reverseArr.append(a[i])
   }
   return reverseArr
}