Swift中的反向范围

时间:2014-06-23 18:10:31

标签: swift

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

例如:

for i in 5...1 {
  // do something
}

是一个无限循环。

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

7 个答案:

答案 0 :(得分:160)

更新最新的Swift 3(仍可在Swift 4中使用)

您可以在范围

上使用reversed()方法
for i in (1...5).reversed() { print(i) } // 5 4 3 2 1

stride(from:through:by:)方法

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

stide(from:to:by:)类似,但不包括最后一个值

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

更新最新的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

它也适用于Doubles

for i in 0.5.stride(to:-0.1, by: -0.1) { print(i) }

警惕浮点数比较边界。

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

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

for i in reverse(1...5) { println(i) } // prints 5,4,3,2,1

0x7fffffff 发布时,有一个新的 stride 结构,可用于通过任意整数进行迭代和递增。 Apple还表示将支持浮点支持。

来自他的回答:

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
}

答案 1 :(得分:19)

这种不对称有些令人不安:

for i in (1..<5).reverse()

......而不是:

for i in 1..<5 {

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

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

infix operator >>> {
    associativity none
    precedence 135
}

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

所以现在我可以说:

for i in 5>>>1 {print(i)} // 4, 3, 2, 1

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

我遇到了运营商的内部危机。我本来希望使用>..,因为它与..<相反,但这不合法:看起来,你不能在非点之后使用点。我考虑过..>,但认为很难区分..<。关于>>>的好处是它尖叫着你:“ down to!” (当然你可以自由地想出另一个算子。但我的建议是:对于超对称,定义<<<来做..<做的事,现在你已经<<<>>>对称且易于输入。)

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

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

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

答案 2 :(得分:9)

看来这个问题的答案已经发生了一些变化,因为我们已经通过了测试版。从测试版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
}

2:使用beta 4中添加的新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
}

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

编辑:在Xcode 6 beta 5 release notes中,Apple添加了以下建议来处理此问题:

  

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

这是一个例子。

for i in lazy(0...5).reverse() {
    // 0, 1, 2, 3, 4, 5
}

答案 3 :(得分:5)

Xcode 7,beta 2:

for i in (1...5).reverse() {
  // do something
}

答案 4 :(得分:3)

Swift 3,4 + :你可以这样做:

for i in sequence(first: 10, next: {$0 - 1}) {

    guard i >= 0 else {
        break
    }
    print(i)
}

结果:10,9,8 ... 0

您可以根据自己的喜好自定义它。有关详情,请阅读func sequence<T> reference

答案 5 :(得分:0)

这可能是另一种方法。

(1...5).reversed().forEach { print($0) }

答案 6 :(得分:-1)

Reverse()函数用于反向编号。

变量n:Int //输入数字

对于1中的i ... n.reverse() {         打印(i) }