首页 文章

如何在swift中以相反的顺序迭代循环?

提问于
浏览
136

当我在Playground中使用for循环时,一切正常,直到我将for循环的第一个参数更改为最高值 . (按降序迭代)

这是一个错误吗?有其他人有吗?

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

显示将要执行的迭代次数的计数器一直在滴答作响......

enter image description here

13 回答

  • 165

    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
    }
    
  • 3

    In Swift 4 and latter

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

    您可以使用reversed()方法轻松反转值 .

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

    reversed()方法反转了这些值 .

  • 1

    如果一个人想要反向迭代一个数组( Array 或更一般地任何 SequenceType ) . 您还有一些其他选择 .

    首先你可以 reverse() 数组并正常循环它 . 但是我更喜欢在很多时候使用 enumerate() ,因为它输出一个包含对象及其索引的元组 .

    这里要注意的一件事是以正确的顺序调用它们很重要:

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

    按降序产生索引(这是我通常所期望的) . 然而:

    for (index, element) in array.reverse().enumerate() (与NSArray的 reverseEnumerator 更接近)

    向后走数组但输出升序索引 .

  • 15

    针对Swift 3进行了更新

    以下答案是可用选项的摘要 . 选择最适合您需求的产品 .

    颠倒:范围内的数字

    Forward

    for index in 0..<5 {
        print(index)
    }
    
    // 0
    // 1
    // 2
    // 3
    // 4
    

    Backward

    for index in (0..<5).reversed() {
        print(index)
    }
    
    // 4
    // 3
    // 2
    // 1
    // 0
    

    颠倒:SequenceType中的元素

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

    Forward

    for animal in animals {
        print(animal)
    }
    
    // horse
    // cow
    // camel
    // sheep
    // goat
    

    Backward

    for animal in animals.reversed() {
        print(animal)
    }
    
    // goat
    // sheep
    // camel
    // cow
    // horse
    

    颠倒:带索引的元素

    有时在迭代集合时需要索引 . 为此你可以使用 enumerate() ,它返回一个元组 . 元组的第一个元素是索引,第二个元素是对象 .

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

    Forward

    for (index, animal) in animals.enumerated() {
        print("\(index), \(animal)")
    }
    
    // 0, horse
    // 1, cow
    // 2, camel
    // 3, sheep
    // 4, goat
    

    Backward

    for (index, animal) in animals.enumerated().reversed()  {
        print("\(index), \(animal)")
    }
    
    // 4, goat
    // 3, sheep
    // 2, camel
    // 1, cow
    // 0, horse
    

    请注意,正如Ben Lachman在his answer中指出的那样,您可能想要 .enumerated().reversed() 而不是 .reversed().enumerated() (这会使索引号增加) .

    步幅:数字

    Stride是在不使用范围的情况下迭代的方法 . 有两种形式 . 代码末尾的注释显示了范围版本(假设增量大小为1) .

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

    Forward

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

    Backward

    将增量大小更改为 -1 可以让您向后移动 .

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

    注意 tothrough 的区别 .

    stride:SequenceType的元素

    Forward by increments of 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
    

    Backward

    for index in stride(from: 4, through: 0, by: -1) {
        print("\(index), \(animals[index])")
    }
    
    // 4, goat
    // 3, sheep 
    // 2, camel
    // 1, cow  
    // 0, horse
    

    注意事项

    • @matt有an interesting solution,他定义了自己的反向运算符并将其称为 >>> . 它不需要很多代码来定义,并使用如下:
    for index in 5>>>0 {
        print(index)
    }
    
    // 4
    // 3
    // 2
    // 1
    // 0
    
  • 1

    您可以考虑使用C-Style while 循环 . 这在Swift 3中运行得很好:

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

    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 成员函数 . 它们是返回 StrideToStrideThrough 结构的全局函数,它们的定义与 Range 结构不同 .

    此答案的先前版本使用 Range 结构的 by() 成员函数,该函数已在测试版4中删除 . 如果您想查看其工作原理,请查看编辑历史记录 .

  • 2

    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
    
  • 39

    对于Swift 2.0及更高版本,您应该对范围集合应用反向

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

    它已在Swift 3.0中重命名为.reversed()

  • 76

    as for Swift 2.2 , Xcode 7.3 (10,June,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)")
    }
    

    Output :

    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
    
  • 7

    将反向函数应用于范围以向后迭代:

    对于 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 答案 .


    要避免创建大型数组,请使用 lazyreverse() . 以下测试在Playground中高效运行,显示它没有创建一个万亿 Int 的数组!

    Test:

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

    对于Xcode 7中的 Swift 2.0

    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
    }
    
  • 24
    var sum1 = 0
    for i in 0...100{
        sum1 += i
    }
    print (sum1)
    
    for i in (10...100).reverse(){
        sum1 /= i
    }
    print(sum1)
    
  • 1

    使用Swift 3,根据您的需要,您可以选择其中一个 eight following Playground code implementations 来解决您的问题 .


    #1 . 使用CountableClosedRange reversed()方法

    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 . 使用CountableRange的reverse()方法

    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)>
    

    返回由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
    */
    

    #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是progress中的最后一个小于或等于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 . 使用AnyIterator init(_ :)初始化程序

    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 . 使用AnyIterator init(_ :)初始化程序

    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
    */
    

相关问题