Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用函数Swift求Fibonacci项之和_Swift_Functional Programming - Fatal编程技术网

用函数Swift求Fibonacci项之和

用函数Swift求Fibonacci项之和,swift,functional-programming,Swift,Functional Programming,我试图学习功能性Swift,并开始从Project Euler做一些练习 偶斐波那契数 问题2 斐波那契序列中的每个新项都是通过将前两项相加生成的。从1和2开始,前10个术语将是: 1、2、3、5、8、13、21、34、55、89 通过考虑Fibonacci序列中值不超过400万的项,求偶数值项之和 根据WWDC advanced Swift视频,实现了记忆化斐波那契函数: func memoize<T:Hashable, U>( body: ((T)->U,T) ->

我试图学习功能性Swift,并开始从Project Euler做一些练习

偶斐波那契数 问题2 斐波那契序列中的每个新项都是通过将前两项相加生成的。从1和2开始,前10个术语将是:

1、2、3、5、8、13、21、34、55、89

通过考虑Fibonacci序列中值不超过400万的项,求偶数值项之和

根据WWDC advanced Swift视频,实现了记忆化斐波那契函数:

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) }
问题的第一个(非功能性)解决方案:

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)
我想改进这个解决方案,因为begging的
1…40
范围无缘无故计算了太多术语。理想情况下,我希望能够有某种无限范围,但同时只计算满足
takeWhile


有什么建议吗?

这里我生成的序列在达到最大值后已经停止。 然后,您只需在不进行过滤的情况下进行缩减,当
n
为奇数时,只需求和0即可

func fibonacciTo(max: Int) -> SequenceOf<Int> {
    return SequenceOf { _ -> GeneratorOf<Int> in
        var (a, b) = (1, 0)
        return GeneratorOf {
            (b, a) = (a, b + a)
            if b > max { return nil }
            return b
        }
    }
}


let sum = reduce(fibonacciTo(4_000_000), 0) {a, n in (n % 2 == 0) ? a + n : a }
希望这有帮助

有一个
filter()
函数,它将序列作为参数:

func filter<S : SequenceType>(source: S, includeElement: (S.Generator.Element) -> Bool) -> [S.Generator.Element]
你们得到一个偶数斐波那契数的“无限”序列。你不能 在该序列上调用ExSwift的
.takeWhile()
方法,因为
.takeWhile()
仅为
struct SequenceOf
定义,而不是为 一般顺序。但是

TakeWhileSequence(
    lazy(FibonacciSequence()).filter ( { $0 % 2 == 0 }),
    { $0 < 4_000_000 }
)
TakeWhileSequence(
惰性(FibonacciSequence()).filter({$0%2==0}),
{ $0 < 4_000_000 }
)
工作并给出所有小于的偶数斐波那契数的序列 4,000,000. 然后

let sum = reduce(TakeWhileSequence(
    lazy(FibonacciSequence()).filter ( { $0 % 2 == 0 }),
    { $0 < 4_000_000 }), 0, +)
let sum=reduce(TakeWhileSequence(
惰性(FibonacciSequence()).filter({$0%2==0}),
{ $0 < 4_000_000 }), 0, +)
给出预期结果并仅计算“必要的” 斐波那契数

请注意,实际上不需要记忆斐波那契数 因为它们是按顺序访问的。同时(如@Matteo) 已经注意到),所有斐波那契数都是整数。所以你可以 将序列更简单地定义为

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
        };
    }
}
struct FibonacciSequence:SequenceType{
func generate()->GeneratorOf{
无功电流=1
var next=1
返回生成器of(){
让结果=电流
当前=下一个
下一个+=结果
返回结果
};
}
}

上述计算仍然有效。

通过使用Swift的惰性序列,您可以非常接近您想要的结果。如果你用斐波那契数生成器(我用的是:)

var(a,b)=(1,0)
var fibs=发电机{
(b,a)=(a,b+a)
返回b
}
您可以将其包装为lazy():

var(a,b)=(1,0)
var fibs=懒惰(
发电机{
(b,a)=(a,b+a)
返回b
}
)
将其作为惰性函数公开给filter()。此筛选器()返回:

LazySequence
现在,要获得takeWhile()函数,需要扩展LazySequence:

extension LazySequence {

  func takeWhile(condition: S.Generator.Element -> Bool)
    -> LazySequence<GeneratorOf<S.Generator.Element>> {

    var gen = self.generate()

    return lazy( GeneratorOf{ gen.next().flatMap{ condition($0) ? $0 : nil }})

  }
}
扩展懒散序列{ func takeWhile(条件:S.Generator.Element->Bool) ->懒散序列{ var gen=self.generate() 返回lazy(GeneratorOf{gen.next().flatMap{condition($0)?$0:nil}) } } 因此,如果基础序列结束或条件不满足,它将返回nil(停止生成器)

综上所述,给定数字下的斐波那契序列看起来非常像您想要的:

fibs
  .filter {$0 % 2 == 0}
  .takeWhile {$0 < 100}

//2, 8, 34
fibs
.filter{$0%2==0}
.takeWhile{$0<100}
//2, 8, 34
但是,因为reduce不是LazySequence上的方法,所以必须转换为数组:

fibs
  .filter {$0 % 2 == 0}
  .takeWhile {$0 < 100}.array
  .reduce(0, combine: +)

//44
fibs
.filter{$0%2==0}
.takeWhile{$0<100}.array
.reduce(0,合并:+)
//44
您可以对LazySequence进行快速而肮脏的扩展,以获得reduce():

扩展懒散序列{ func reduce(首字母:U,combine:(U,S.Generator.Element)->U)->U{ var accu=初始值 对于自{accu=combine(accu,element)}中的元素 返回累计器 } } 你可以这样写最后一件事:

fibs
  .filter {$0 % 2 == 0}
  .takeWhile {$0 < 100}
  .reduce(0, combine: +)

//44
fibs.prefix{$0 < 4000000}.filter{$0 % 2 == 0}.reduce(0){$0 + $1}
fibs
.filter{$0%2==0}
.takeWhile{$0<100}
.reduce(0,合并:+)
//44

所有这些序列都会持续它们的懒惰——fibs是无限的,所以它们在其他情况下不会真正起作用。事实上,在reduce之前什么都不会计算:在reduce之前都是thunks。

在Swift 3.1中,这里有一个迭代器,可以永远生成斐波那契数,并由此派生出一个无限序列:

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

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

let fibs = AnySequence{FibIterator()}
您可以得到400万以下偶数项的总和,如下所示:

fibs
  .filter {$0 % 2 == 0}
  .takeWhile {$0 < 100}
  .reduce(0, combine: +)

//44
fibs.prefix{$0 < 4000000}.filter{$0 % 2 == 0}.reduce(0){$0 + $1}

顺便说一句,请注意不需要
Double
类型。您可能更喜欢使用
UInt
True,这是我尝试计算phiOk时的一个残余,编辑。。。现在它似乎更实用;-)由于@doisk,我的斐波那契序列中出现了一个错误
fibs
  .filter {$0 % 2 == 0}
  .takeWhile {$0 < 100}

//2, 8, 34
fibs
  .filter {$0 % 2 == 0}
  .takeWhile {$0 < 100}.array
  .reduce(0, combine: +)

//44
extension LazySequence {

  func reduce<U>(initial: U, combine: (U, S.Generator.Element) -> U) -> U {

    var accu = initial

    for element in self { accu = combine(accu, element) }

    return accu

  }
}
fibs
  .filter {$0 % 2 == 0}
  .takeWhile {$0 < 100}
  .reduce(0, combine: +)

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

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

let fibs = AnySequence{FibIterator()}
fibs.prefix{$0 < 4000000}.filter{$0 % 2 == 0}.reduce(0){$0 + $1}
> print( Array(fibs.lazy.filter{$0 % 2 == 0}.prefix(5)) )
[2, 8, 34, 144, 610]