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

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

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

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

显示将要执行的迭代次数的计数器保持滴答作响…

在这里输入图像描述

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结构的全局函数, StrideThrough结构的定义与Range结构不同。

此答案的以前版本使用了Range结构的by()成员函数,该函数在beta 4中已被删除。如果要查看其工作原理,请检查编辑历史logging。

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

对于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)会创build一个[Int]types的数组,所以对于小范围这可能是正确的,如下所示使用lazy会比较明智,或者如果范围很大。


为避免创build大数组,请使用lazyreverse() 。 以下testing在Playground中高效运行,表明它不会创build一个具有一万亿个Int的数组!

testing:

 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()的types是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 } 

更新了Swift 3

下面的答案是可用选项的摘要。 select一个最适合您的需求。

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 

reversedSequenceType元素

 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 

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

迈步:数字

步幅是迭代的方式,而不使用范围。 有两种forms。 代码末尾的注释显示范围版本将会是什么(假定增量大小为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 

注意通和差别。

步幅: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])") } // 0, horse // 1, cow // 2, camel // 3, sheep // 4, goat 

笔记

  • @matt有一个有趣的解决scheme ,他定义了自己的逆运算符并将其称为>>> 。 它不需要太多的代码来定义和使用像这样:

     for index in 5>>>0 { print(index) } // 4 // 3 // 2 // 1 // 0 
  • 查看C风格从Swift中删除的循环3

斯威夫特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 } 

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

使用Swift 3,根据您的需要,您可以select以下八种Playground代码实现中的一种来解决您的问题。


#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 reversed()方法

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

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 - 1 >= 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:)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:)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 

创build一个包装基础迭代器的迭代器,但其types仅取决于基础迭代器的元素types。

用法:

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

创build一个将给定闭包封装在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创build一个扩展方法并将你的迭代器包装在其中来重构以前的代码:

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

如果有人想要反过来遍历数组 (或更一般的任何SequenceType )。 你有一些额外的select。

首先你可以reverse()数组,并像平常一样循环。 不过,我更喜欢使用enumerate() ,因为它输出一个包含对象的元组,并且它是索引。

这里要注意的一点是,以正确的顺序调用这些是非常重要的:

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

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

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

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

至于Swift 2.2,Xcode 7.3(2016年10月10日):

 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 

Swift 4.0

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

如果你想包含的价值:

 for i in stride(from: 5, through: 0, by: -1) { print(i) // 5,4,3,2,1,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 }