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 结构不同 .
此答案的先前版本使用 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)
}
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
*/
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
*/
13 回答
Swift 4.0
如果要包含
to
值:In Swift 4 and latter
您可以使用reversed()方法轻松反转值 .
reversed()方法反转了这些值 .
如果一个人想要反向迭代一个数组(
Array
或更一般地任何SequenceType
) . 您还有一些其他选择 .首先你可以
reverse()
数组并正常循环它 . 但是我更喜欢在很多时候使用enumerate()
,因为它输出一个包含对象及其索引的元组 .这里要注意的一件事是以正确的顺序调用它们很重要:
for (index, element) in array.enumerate().reverse()
按降序产生索引(这是我通常所期望的) . 然而:
for (index, element) in array.reverse().enumerate()
(与NSArray的reverseEnumerator
更接近)向后走数组但输出升序索引 .
针对Swift 3进行了更新
以下答案是可用选项的摘要 . 选择最适合您需求的产品 .
颠倒:范围内的数字
Forward
Backward
颠倒:SequenceType中的元素
Forward
Backward
颠倒:带索引的元素
有时在迭代集合时需要索引 . 为此你可以使用
enumerate()
,它返回一个元组 . 元组的第一个元素是索引,第二个元素是对象 .Forward
Backward
请注意,正如Ben Lachman在his answer中指出的那样,您可能想要
.enumerated().reversed()
而不是.reversed().enumerated()
(这会使索引号增加) .步幅:数字
Stride是在不使用范围的情况下迭代的方法 . 有两种形式 . 代码末尾的注释显示了范围版本(假设增量大小为1) .
Forward
Backward
将增量大小更改为
-1
可以让您向后移动 .注意
to
和through
的区别 .stride:SequenceType的元素
Forward by increments of 2
我在这个例子中使用
2
只是为了表明另一种可能性 .Backward
注意事项
>>>
. 它不需要很多代码来定义,并使用如下:您可以考虑使用C-Style
while
循环 . 这在Swift 3中运行得很好:Xcode 6 beta 4添加了两个函数来迭代范围,其中一个步骤不是一个:
stride(from: to: by:)
,与独占范围一起使用,stride(from: through: by:)
,与包含范围一起使用 .要以相反的顺序迭代范围,可以按如下方式使用它们:
请注意,这些都不是
Range
成员函数 . 它们是返回StrideTo
或StrideThrough
结构的全局函数,它们的定义与Range
结构不同 .此答案的先前版本使用
Range
结构的by()
成员函数,该函数已在测试版4中删除 . 如果您想查看其工作原理,请查看编辑历史记录 .Swift 4 起
对于Swift 2.0及更高版本,您应该对范围集合应用反向
它已在Swift 3.0中重命名为.reversed()
as for Swift 2.2 , Xcode 7.3 (10,June,2016) :
Output :
将反向函数应用于范围以向后迭代:
对于 Swift 1.2 及更早版本:
它也适用于半开放范围:
注意:
reverse(1...10)
创建一个[Int]
类型的数组,所以虽然这对于小范围可能没问题,但如果你的范围很大,最好使用如下所示的lazy
或考虑接受的stride
答案 .要避免创建大型数组,请使用
lazy
和reverse()
. 以下测试在Playground中高效运行,显示它没有创建一个万亿Int
的数组!Test:
对于Xcode 7中的 Swift 2.0 :
请注意,在Swift 2.0中,
(1...1_000_000_000_000).reverse()
的类型为ReverseRandomAccessCollection<(Range<Int>)>
,所以这样可以正常工作:对于 Swift 3.0
reverse()
已重命名为reversed()
:使用Swift 3,根据您的需要,您可以选择其中一个 eight following Playground code implementations 来解决您的问题 .
#1 . 使用CountableClosedRange reversed()方法
CountableClosedRange
有一个名为reversed()的方法 .reversed()
方法有以下声明:用法:
#2 . 使用CountableRange的reverse()方法
CountableRange
有一个名为reversed()的方法 .reversed()
方法有以下声明:用法:
#3 . 使用sequence(first:next :)函数
Swift标准库提供了一个名为sequence(first:next:)的函数 .
sequence(first:next:)
有以下声明:用法:
#4 . 使用stride(from:through:by :)函数
Swift标准库提供了一个名为stride(from:through:by:)的函数 .
stride(from:through:by:)
有以下声明:用法:
#5 . 使用stride(from:to:by :)函数
Swift标准库提供了一个名为stride(from:to:by:)的函数 .
stride(from:to:by:)
有以下声明:用法:
#6 . 使用AnyIterator init(_ :)初始化程序
AnyIterator
有一个名为init(_:)的初始化程序 .init(_:)
有以下声明:用法:
#7 . 使用AnyIterator init(_ :)初始化程序
AnyIterator
有一个名为init(_:)的初始化程序 .init(_:)
有以下声明:用法:
#8 . 使用自定义Int扩展方法
您可以通过为
Int
创建扩展方法并将迭代器包装在其中来重构以前的代码: