Swift中的反向范围

Edu*_*rdo 95 swift

有没有办法在Swift中使用反向范围?

例如:

for i in 5...1 {
  // do something
}
Run Code Online (Sandbox Code Playgroud)

是一个无限循环.

我知道我可以使用1..5,计算j = 6 - i和使用j我的索引.我只是想知道是否有更清晰的东西?

Jac*_*ack 167

更新最新的Swift 3(仍在Swift 4中运行)

您可以reversed()在范围上使用该方法

for i in (1...5).reversed() { print(i) } // 5 4 3 2 1
Run Code Online (Sandbox Code Playgroud)

stride(from:through:by:)方法

for i in stride(from:5,through:1,by:-1) { print(i) } // 5 4 3 2 1
Run Code Online (Sandbox Code Playgroud)

stide(from:to:by:) 类似但排除了最后一个值

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

更新最新的Swift 2

首先,协议扩展改变了reverse使用方式:

for i in (1...5).reverse() { print(i) } // 5 4 3 2 1

Stride已在Xcode 7 Beta 6中重新设计.新用法是:

for i in 0.stride(to: -8, by: -2) { print(i) } // 0 -2 -4 -6
for i in 0.stride(through: -8, by: -2) { print(i) } // 0 -2 -4 -6 -8
Run Code Online (Sandbox Code Playgroud)

它也适用于Doubles:

for i in 0.5.stride(to:-0.1, by: -0.1) { print(i) }
Run Code Online (Sandbox Code Playgroud)

警惕这里的浮点比较边界.

早期编辑Swift 1.2:从Xcode 6 Beta 4开始,byReverseRange不再存在:[

如果您只是想要反转一个范围,那么您只需要反向功能:

for i in reverse(1...5) { println(i) } // prints 5,4,3,2,1
Run Code Online (Sandbox Code Playgroud)

0x7fffffff发布,有一个新的stride构造,可用于迭代和递增任意整数.苹果还表示浮动支持即将到来.

来自他的回答:

for x in stride(from: 0, through: -8, by: -2) {
    println(x) // 0, -2, -4, -6, -8
}

for x in stride(from: 6, to: -2, by: -4) {
    println(x) // 6, 2
}
Run Code Online (Sandbox Code Playgroud)

  • 值得指出的是,"反转"具有O(1)的复杂性,因为它仅包装原始集合,并且不需要迭代来构建它. (3认同)
  • 看起来像swift 3的`stride`代码略有不正确.要包含数字1,你需要使用`to`反对`to`这样:`for i in stride(from:5,through:1,by:-1){print(i)}` (2认同)

mat*_*att 20

这种不对称有些令人不安的问题:

for i in (1..<5).reverse()
Run Code Online (Sandbox Code Playgroud)

......而不是这个:

for i in 1..<5 {
Run Code Online (Sandbox Code Playgroud)

这意味着每次我想做一个反向范围时,我必须记住放括号,加上我必须.reverse()在最后写出来,像拇指一样伸出来.与C风格的for循环相比,这是非常难看的,它们是对称计数和倒计时.所以我倾向于使用C风格的循环代替.但是在Swift 2.2中,C风格的循环正在消失!所以我不得不匆匆忙忙用这个丑陋的.reverse()构造来替换我所有递减的C风格的循环- 一直想知道,为什么地球上没有反向范围的算子呢?

可是等等!这是Swift - 我们被允许定义我们自己的运营商!! 开始了:

infix operator >>> {
    associativity none
    precedence 135
}

func >>> <Pos : ForwardIndexType where Pos : Comparable>(end:Pos, start:Pos)
    -> ReverseRandomAccessCollection<(Range<Pos>)> {
        return (start..<end).reverse()
}
Run Code Online (Sandbox Code Playgroud)

所以现在我可以说:

for i in 5>>>1 {print(i)} // 4, 3, 2, 1
Run Code Online (Sandbox Code Playgroud)

这仅仅涵盖了我的代码中最常见的情况,但它最常见的情况,所以这就是我目前所需要的.

我对运营商提出了一种内部危机.我本来想使用>..,反之亦然..<,但这不合法:看起来你不能在非点之后使用点.我考虑过..>但是认为它太难以区分了..<.好消息>>>是它尖叫着你:" 到!" (当然你可以自由地想出另一个操作员.但我的建议是:对于超对称,定义<<<做什么..<,现在你已经得到了<<<,>>>哪些是对称的,易于打字.)


Swift 3版本(Xcode 8种子6):

infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound) ->
    ReversedRandomAccessCollection<CountableRange<Bound>> 
    where Bound : Comparable, Bound.Stride : Integer {
        return (minimum..<maximum).reversed()
}
Run Code Online (Sandbox Code Playgroud)

Swift 4版本(Xcode 9 beta 3):

infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound)
    -> ReversedRandomAccessCollection<CountableRange<Bound>>
    where Bound : Comparable & Strideable { 
        return (minimum..<maximum).reversed()
}
Run Code Online (Sandbox Code Playgroud)

Swift 4.2版本(Xcode 10 beta 1):

infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound)
    -> ReversedRandomAccessCollection<Range<Bound>>
    where Bound : Strideable { 
        return (minimum..<maximum).reversed()
}
Run Code Online (Sandbox Code Playgroud)


Mic*_*lum 9

看来这个问题的答案在我们通过测试版进展时有所改变.从beta 4开始,by()函数和ReversedRange类型都已从语言中删除.如果您想要制作相反的范围,您的选项现在如下:

1:创建前向范围,然后使用该reverse()功能将其反转.

for x in reverse(0 ... 4) {
    println(x) // 4, 3, 2, 1, 0
}

for x in reverse(0 ..< 4) {
    println(x) // 3, 2, 1, 0
}
Run Code Online (Sandbox Code Playgroud)

2:使用stride()beta 4中添加的新功能,其中包括指定起始和结束索引的函数,以及要迭代的数量.

for x in stride(from: 0, through: -8, by: -2) {
    println(x) // 0, -2, -4, -6, -8
}

for x in stride(from: 6, to: -2, by: -4) {
    println(x) // 6, 2
}
Run Code Online (Sandbox Code Playgroud)

请注意,我在这篇文章中也包括了新的独家范围操作符...被替换为..<.

编辑:从Xcode 6 beta 5发行说明中,Apple添加了以下建议来处理此问题:

ReverseRange已被删除; 使用懒惰(x ..

这是一个例子.

for i in lazy(0...5).reverse() {
    // 0, 1, 2, 3, 4, 5
}
Run Code Online (Sandbox Code Playgroud)


lea*_*nne 5

Xcode 7,beta 2:

for i in (1...5).reverse() {
  // do something
}
Run Code Online (Sandbox Code Playgroud)