如何在swift中以相反的顺序迭代循环?

Kri*_*nan 174 ios swift swift-playground

当我在Playground中使用for循环时,一切正常,直到我将for循环的第一个参数更改为最高值.(按降序迭代)

这是一个错误吗?还有其他人有吗?

for index in 510..509
{
    var a = 10
}
Run Code Online (Sandbox Code Playgroud)

显示将要执行的迭代次数的计数器一直在滴答作响......

在此输入图像描述

Cez*_*zar 205

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
Run Code Online (Sandbox Code Playgroud)

请注意,这些都不是Range成员函数.它们是返回a StrideToStrideThroughstruct的全局函数,它们的结构与Rangestruct 不同.

此答案的先前版本使用了struct 的by()成员函数,该Range函数已在beta 4中删除.如果要查看其工作原理,请查看编辑历史记录.

  • 现在使用Swift 2.0:`5.stride(to:1,by:-1)`或`5.stride(through:1,by:-1)` (24认同)
  • 使用Swift 3.0,我们又回到了自由功能的步伐. (4认同)

vac*_*ama 204

将反向函数应用于范围以向后迭代:

对于Swift 1.2及更早版本:

// Print 10 through 1
for i in reverse(1...10) {
    println(i)
}
Run Code Online (Sandbox Code Playgroud)

它也适用于半开放范围:

// Print 9 through 1
for i in reverse(1..<10) {
    println(i)
}
Run Code Online (Sandbox Code Playgroud)

注意: reverse(1...10)创建一个类型的数组[Int],因此虽然这对于小范围可能没问题,但如果你的范围很大,最好使用lazy如下所示的方法或考虑接受的stride答案.


要避免创建大型数组,请lazy同时使用reverse().以下测试在Playground中高效运行,表明它没有创建一万亿Int秒的阵列!

测试:

var count = 0
for i in lazy(1...1_000_000_000_000).reverse() {
    if ++count > 5 {
        break
    }
    println(i)
}
Run Code Online (Sandbox Code Playgroud)

对于Xcode 7中的Swift 2.0:

for i in (1...10).reverse() {
    print(i)
}
Run Code Online (Sandbox Code Playgroud)

请注意,在Swift 2.0中,(1...1_000_000_000_000).reverse()是类型ReverseRandomAccessCollection<(Range<Int>)>,所以这工作正常:

var count = 0
for i in (1...1_000_000_000_000).reverse() {
    count += 1
    if count > 5 {
        break
    }
    print(i)
}
Run Code Online (Sandbox Code Playgroud)

对于Swift 3.0 reverse()已被重命名为reversed():

for i in (1...10).reversed() {
    print(i) // prints 10 through 1
}
Run Code Online (Sandbox Code Playgroud)

  • 我发现使用`stride`函数更容易阅读. (7认同)
  • 但是,"反向"可能会复制该系列.至少,这就是我对"数据"的文档的理解. (3认同)

Sur*_*gch 87

针对Swift 3进行了更新

以下答案是可用选项的摘要.选择最适合您需求的产品.

reversed:范围内的数字

向前

for index in 0..<5 {
    print(index)
}

// 0
// 1
// 2
// 3
// 4
Run Code Online (Sandbox Code Playgroud)

向后

for index in (0..<5).reversed() {
    print(index)
}

// 4
// 3
// 2
// 1
// 0
Run Code Online (Sandbox Code Playgroud)

reversed:元素 SequenceType

let animals = ["horse", "cow", "camel", "sheep", "goat"]
Run Code Online (Sandbox Code Playgroud)

向前

for animal in animals {
    print(animal)
}

// horse
// cow
// camel
// sheep
// goat
Run Code Online (Sandbox Code Playgroud)

向后

for animal in animals.reversed() {
    print(animal)
}

// goat
// sheep
// camel
// cow
// horse
Run Code Online (Sandbox Code Playgroud)

reversed:带索引的元素

有时在迭代集合时需要索引.为此你可以使用enumerate(),它返回一个元组.元组的第一个元素是索引,第二个元素是对象.

let animals = ["horse", "cow", "camel", "sheep", "goat"]
Run Code Online (Sandbox Code Playgroud)

向前

for (index, animal) in animals.enumerated() {
    print("\(index), \(animal)")
}

// 0, horse
// 1, cow
// 2, camel
// 3, sheep
// 4, goat
Run Code Online (Sandbox Code Playgroud)

向后

for (index, animal) in animals.enumerated().reversed()  {
    print("\(index), \(animal)")
}

// 4, goat
// 3, sheep
// 2, camel
// 1, cow
// 0, horse
Run Code Online (Sandbox Code Playgroud)

请注意,正如Ben Lachman在他的回答中指出的那样,你可能想做.enumerated().reversed()而不是.reversed().enumerated()(这将使索引号增加).

大步:数字

Stride是在不使用范围的情况下迭代的方法.有两种形式.代码末尾的注释显示了范围版本(假设增量大小为1).

startIndex.stride(to: endIndex, by: incrementSize)      // startIndex..<endIndex
startIndex.stride(through: endIndex, by: incrementSize) // startIndex...endIndex
Run Code Online (Sandbox Code Playgroud)

向前

for index in stride(from: 0, to: 5, by: 1) {
    print(index)
}

// 0
// 1
// 2
// 3
// 4
Run Code Online (Sandbox Code Playgroud)

向后

更改增量大小以-1允许您向后移动.

for index in stride(from: 4, through: 0, by: -1) {
    print(index)
}

// 4
// 3
// 2
// 1
// 0
Run Code Online (Sandbox Code Playgroud)

注意tothrough区别.

stride:SequenceType的元素

以2为增量转发

let animals = ["horse", "cow", "camel", "sheep", "goat"]
Run Code Online (Sandbox Code Playgroud)

2在这个例子中使用的只是为了显示另一种可能性.

for index in stride(from: 0, to: 5, by: 2) {
    print("\(index), \(animals[index])")
}

// 0, horse
// 2, camel
// 4, goat
Run Code Online (Sandbox Code Playgroud)

向后

for index in stride(from: 4, through: 0, by: -1) {
    print("\(index), \(animals[index])")
}

// 4, goat
// 3, sheep 
// 2, camel
// 1, cow  
// 0, horse 
Run Code Online (Sandbox Code Playgroud)

笔记


Irf*_*fan 50

斯威夫特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
Run Code Online (Sandbox Code Playgroud)


And*_*uca 27

对于Swift 2.0及更高版本,您应该对范围集合应用反向

for i in (0 ..< 10).reverse() {
  // process
}
Run Code Online (Sandbox Code Playgroud)

它已在Swift 3.0中重命名为.reversed()


Ima*_*tit 25

使用Swift 4.2,根据您的需要,您可以选择以下四个Playground代码示例中的一个来解决您的问题.


#1.使用ClosedRange reversed()方法

ClosedRange有一个叫做的方法reversed().reversed()方法有以下声明:

func reversed() -> ReversedCollection<ClosedRange<Bound>>
Run Code Online (Sandbox Code Playgroud)

返回以相反顺序显示集合元素的视图.

用法:

let reversedCollection = (0 ... 5).reversed()

for index in reversedCollection {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/
Run Code Online (Sandbox Code Playgroud)

作为替代方案,您可以使用Range reversed()方法:

let reversedCollection = (0 ..< 6).reversed()

for index in reversedCollection {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/
Run Code Online (Sandbox Code Playgroud)

#2.使用sequence(first:next:)功能

Swift标准库提供了一个名为的函数sequence(first:next:).sequence(first:next:)有以下声明:

func sequence<T>(first: T, next: @escaping (T) -> T?) -> UnfoldFirstSequence<T>
Run Code Online (Sandbox Code Playgroud)

返回由first惰性应用程序形成并重复的延迟应用程序next.

用法:

let unfoldSequence = sequence(first: 5, next: {
    $0 > 0 ? $0 - 1 : nil
})

for index in unfoldSequence {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/
Run Code Online (Sandbox Code Playgroud)

#3.使用stride(from:through:by:)功能

Swift标准库提供了一个名为的函数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
Run Code Online (Sandbox Code Playgroud)

返回从起始值开始的序列,并且可能包括结束值,步长为指定的量.

用法:

let sequence = stride(from: 5, through: 0, by: -1)

for index in sequence {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/
Run Code Online (Sandbox Code Playgroud)

作为替代方案,您可以使用stride(from:to:by:):

let sequence = stride(from: 5, to: -1, by: -1)

for index in sequence {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/
Run Code Online (Sandbox Code Playgroud)

#4.使用AnyIterator init(_:)初始化程序

AnyIterator有一个初始化程序称为init(_:).init(_:)有以下声明:

init(_ body: @escaping () -> AnyIterator<Element>.Element?)
Run Code Online (Sandbox Code Playgroud)

创建一个迭代器,在其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
*/
Run Code Online (Sandbox Code Playgroud)

如果需要,您可以通过为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
*/
Run Code Online (Sandbox Code Playgroud)


Roh*_*dia 8

在Swift 4和后者中

    let count = 50//For example
    for i in (1...count).reversed() {
        print(i)
    }
Run Code Online (Sandbox Code Playgroud)


Wil*_* Hu 5

迅捷4.0

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

如果要包括to值:

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