微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用Functional Swift的Fibonacci项的和

我正在尝试学习函数 Swift并开始从Project Euler做一些练习.

Even Fibonacci numbers
Problem 2
Each new term in the Fibonacci sequence is generated by adding the prevIoUs two terms. By starting with 1 and 2,the first 10 terms will be:

1,2,3,5,8,13,21,34,55,89,…

By considering the terms in the Fibonacci sequence whose values do not exceed four million,find the sum of the even-valued terms.

根据WWDC高级Swift视频实现了一个memoized斐波那契函数

func memoize<T:Hashable,U>( body: ((T)->U,T) -> U) -> (T)->U {
  var memo = [T:U]()
  var result: ((T)->U)!
  result = { x in
    if let q = memo[x] { return q }
    let r = body(result,x)
    memo[x] = r
    return r
  }
  return result
}

let fibonacci = memoize { (fibonacci:Int->Double,n:Int) in n < 2 ? Double(n) : fibonacci(n-1) + fibonacci(n-2) }

并实现了一个符合Sequence协议的类

class FibonacciSequence: SequenceType {
  func generate() -> GeneratorOf<Double> {
      var n = 0
      return GeneratorOf<Double> { fibonacci(n++) }
  }

  subscript(n: Int) -> Double {
      return fibonacci(n)
  }
}

问题的第一个(非功能性)解决方案:

var fib = FibonacciSequence().generate()
var n:Double = 0
var sum:Double = 0
while n < Double(4_000_000) {
  if n % 2 == 0 {
    sum += n
  }
n = fib.next()!
}

println(sum)

第二个更实用的解决方案,使用ExSwift的takeWhile功能

let f = FibonacciSequence()
println((1...40).map { f[$0] }
                .filter { $0 % 2 == 0 }
                .takeWhile { $0 < 4_000_000 }
                .reduce(0,combine: +))

我想改进这个解决方案,因为乞讨的1 … 40范围无缘无故地计算了太多的术语.理想情况下,我希望能够拥有某种无限范围,但同时只计算满足条件的所需条款

有什么建议 ?

解决方法

一个filter()函数,它接受一个序列作为参数:

func filter<S : SequenceType>(source: S,includeElement: (S.Generator.Element) -> Bool) -> [S.Generator.Element]

但由于返回值是一个数组,如果你愿意,这不适合
使用“无限”序列.但随着

lazy(FibonacciSequence()).filter ( { $0 % 2 == 0 })

你得到了一个偶数斐波纳契数的“无限”序列.你不能
在该序列上调用ExSwift的.takeWhile()方法,因为
.takeWhile()仅为struct SequenceOf定义,而不是为
一般序列.但

TakeWhileSequence(
    lazy(FibonacciSequence()).filter ( { $0 % 2 == 0 }),{ $0 < 4_000_000 }
)

工作并给出所有偶数斐波纳契数的序列小于
4000000.然后

let sum = reduce(TakeWhileSequence(
    lazy(FibonacciSequence()).filter ( { $0 % 2 == 0 }),{ $0 < 4_000_000 }),+)

给出预期结果并仅计算“必要”
斐波纳契数.

请注意,实际上不需要记住Fibonacci数字
这是因为它们是按顺序访问的.另外(作为@Matteo
已经注意到了),所有Fibonacci数都是整数.所以你可以
将序列更简单地定义为

struct FibonacciSequence : SequenceType {

    func generate() -> GeneratorOf<Int> {
        var current = 1
        var next = 1
        return GeneratorOf<Int>() {
            let result = current
            current = next
            next += result
            return result
        };
    }
}

而上述计算仍然有效.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐