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


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

это ошибка? У кого-нибудь еще она была?

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

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

13 128

13 ответов:

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 функции-члена. Это глобальные функции, которые возвращают либо a StrideTo или StrideThrough структуры, которые определяются иначе, чем Range структура.

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

применить обратную функцию к диапазону, чтобы выполнить итерации в обратном направлении:

на 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(). Следующий тест выполняется эффективно на игровой площадке, показывая, что он не создает массив с одним триллионом Ints!

обновлено для 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 разницы.

stride: элементы 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 

Примечания

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

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

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

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

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


#1. Используя CountableClosedRangereversed() метод

CountableClosedRange имеет метод под названием reversed(). reversed() метод имеет следующее объявление:

func reversed() -> ReversedRandomAccessCollection<CountableClosedRange<Bound>>

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

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

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

for index in reversedRandomAccessCollection {
    print(index)
}

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

#2. Используя CountableRangereversed() метод

CountableRange имеет метод под названием reversed(). reversed() метод имеет следующее объявление:

func reversed() -> ReversedRandomAccessCollection<CountableRange<Bound>>

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

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

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

for index in reversedRandomAccessCollection {
    print(index)
}

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

#3. Используя sequence(first:next:) функция

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

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

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

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

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

for index in unfoldSequence {
    print(index)
}

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

#4. Используя 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

возвращает последовательность значений (self, self + stride, self + 2 * stride, … last) где last-последнее значение в прогрессии меньше или равно end.

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

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

for index in sequence {
    print(index)
}

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

#5. Используя stride(from:to:by:) функции

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

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

возвращает последовательность значений (self, self + stride, self + 2 * stride, … last) где last-последнее значение в прогрессии, которое меньше end.

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

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

for index in sequence {
    print(index)
}

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

#6. Используя AnyIteratorinit(_:) инициализатор

AnyIterator имеет инициализатор под названием init(_:). init(_:) есть следующее объявление:

init<I>(_ base: I) where I : IteratorProtocol, I.Element == Element

создает итератор, который обертывает базовый итератор, но тип которого зависит только от типа элемента базового итератора.

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

var index = 5

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

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

for index in iterator {
    print(index)
}

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

#7. Используя AnyIteratorinit(_:) инициализатор

AnyIterator имеет инициализатор под названием init(_:). init(_:) есть следующее объявление:

init(_ body: @escaping () -> AnyIterator.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
*/

#8. Использование пользовательского Int метод расширения

вы можете реорганизовать предыдущий код, создав метод расширения для 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
*/

в Swift 4 и latter

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

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
}

если кто-то хочет перебрать массив (Array или вообще любой SequenceType) в обратном направлении. У вас есть несколько дополнительных опций.

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

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

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

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

for (index, element) in array.reverse().enumerate() (который является гораздо ближе к )

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

Что касается 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
var sum1 = 0
for i in 0...100{
    sum1 += i
}
print (sum1)

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

вы можете рассмотреть возможность использования C-Style while вместо петли. Это работает просто отлично в Swift 3:

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

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

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

метод reversed () изменяет значения на противоположные.