Swift中的反向范围

rm5edbpk  于 2022-12-22  发布在  Swift
关注(0)|答案(7)|浏览(109)

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

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

是一个无限循环。
在较新版本的Swift中,该代码可以编译,但在运行时会出现错误:
致命错误:无法形成上限〈下限的范围
我知道我可以用1..5来代替,计算j = 6 - i并使用j作为我的索引。我只是想知道是否有更清晰的东西?

dgenwo3n

dgenwo3n1#

针对最新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

stride(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开始,byReverseRange不再存在:[

如果您只是想反转一个范围,则只需使用reverse函数即可:

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

正如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
}
2lpgd968

2lpgd9682#

这种不对称性有一些令人不安的地方:

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

......与此相反:

for i in 1..<5 {

这意味着每次我想做一个反向范围,我必须记住把括号,加上我必须写在最后的.reverse(),突出像一个拇指痛,这是真的很难看相比,C风格的循环,这是对称的向上计数和向下计数,所以我倾向于使用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测试版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测试版1):

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

Swift 5版本(Xcode 10.2.1):

infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound)
    -> ReversedCollection<Range<Bound>>
    where Bound : Strideable {
        return (minimum..<maximum).reversed()
}
ddarikpa

ddarikpa3#

这个问题的答案似乎随着测试版的进展而有所改变。从测试版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中添加了以下建议来处理这个问题:

已移除ReverseRange;使用lazy(x..
这里有一个例子。

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

f1tvaqid4#

Xcode 7,测试版2 (〈Swift 3.0)

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

根据Developer Documentation, available as of 8 Dec 2020更新Xcode 8.0+(Swift 3.0+)

  • 要 * 反向迭代 * 集合而不更改集合的内容,请使用reversed-
let word = "Backwards"
for char in word.reversed() {
    print(char, terminator: "")
}
// Prints "sdrawkcaB"

在这种情况下,集合周围的 Package 读取集合的内容,并以相反的顺序返回它们。

  • 要 * 反转集合的内容 *,请使用类型初始化器,并为它提供集合reversed。这将创建一个具有相同内容但被反转的新集合:
let reversedWord = String(word.reversed())
print(reversedWord)
// Prints "sdrawkcaB"
  • 此外,可以使用泛型函数stride(from:to:by:)反向返回集合的内容(以及按正常顺序):
for countdown in stride(from: 3, to: 0, by: -1) {
    print("\(countdown)...")
}
// 3...
// 2...
// 1...

如果from值大于to值,并且by值为负,则stride反向读取内容。
如果from值小于to值,并且by值为正,则stride将按其原始顺序通读内容。

  • 注意:* 集合包括数组、集合、字典以及其他特殊的集合。只要集合是可迭代的,这些技术就可以工作。
  • 2nd注:* 截至2020年12月8日,Swift版本及其相关的Xcode版本可以在https://swiftly.dev/swift-versions上找到。根据这一参考,Xcode 8.0+与Swift 3.0相关联,这是reverse()成为reversed()的时候。
t98cgbkg

t98cgbkg5#

雨燕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

kadbb459

kadbb4596#

这可能是另一种方法。

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

txu3uszq7#

Reverse()函数用于倒序编号。
变量n:整数//输入数字
对于1...n.reverse()中的i {打印(i)}

相关问题