如何快速检测IteratorProtocol的首次运行?

时间:2018-08-30 15:45:14

标签: ios swift algorithm fibonacci iterator-protocol

尝试检测Iterator协议的首次运行。 在下面的示例中,我尝试从零开始打印斐波那契数列,但从一开始:

class FibIterator : IteratorProtocol {
var (a, b) = (0, 1)

func next() -> Int? {
    (a, b) = (b, a + b)
    return a
}
}

let fibs = AnySequence{FibIterator()}

print(Array(fibs.prefix(10)))

可以对上述代码进行哪些修改以检测首次运行?

1 个答案:

答案 0 :(得分:1)

要回答您的逐字记录问题:您可以添加一个布尔变量 firstRun来检测next()方法的第一次调用:

class FibIterator : IteratorProtocol {
    var firstRun = true
    var (a, b) = (0, 1)

    func next() -> Int? {
        if firstRun {
            firstRun = false
            return 0
        }
        (a, b) = (b, a + b)
        return a
    }
}

let fibs = AnySequence { FibIterator() }
print(Array(fibs.prefix(10))) // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

但是对于此问题有更完善的解决方案。 您可以“推迟”对ab的更新,在返回后 当前值:

class FibIterator : IteratorProtocol {
    var (a, b) = (0, 1)

    func next() -> Int? {
        defer { (a, b) = (b, a + b) }
        return a
    }
}

let fibs = AnySequence { FibIterator() }
print(Array(fibs.prefix(10))) // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

或-也许更简单-更改初始值(使用事实 斐波那契数也为负数定义)

class FibIterator : IteratorProtocol {
    var (a, b) = (1, 0)  // (Fib(-1), Fib(0))

    func next() -> Int? {
        (a, b) = (b, a + b)
        return a
    }
}

let fibs = AnySequence { FibIterator() }
print(Array(fibs.prefix(10))) // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

请注意,如果您声明符合Sequence协议 那么您就不需要AnySequence包装器了(默认情况下 makeIterator()的实现符合类型 IteratorProtocol)。值类型通常也是首选, 因此-除非需要引用语义-您可以将其设置为struct

struct FibSequence : Sequence, IteratorProtocol {
    var (a, b) = (1, 0)  // (Fib(-1), Fib(0))

    mutating func next() -> Int? {
        (a, b) = (b, a + b)
        return a
    }
}

let fibs = FibSequence()