如何在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
成员函数。 它们是返回StrideTo
或StrideThrough
结构的全局函数, 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大数组,请使用lazy
和reverse()
。 以下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
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
请注意,正如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 }