在Scala中生成一系列Fibonacci数

时间:2012-03-25 22:03:06

标签: scala sequence list-comprehension fibonacci


  def fibSeq(n: Int): List[Int] = {
    var ret = scala.collection.mutable.ListBuffer[Int](1, 2)
    while (ret(ret.length - 1) < n) {
      val temp = ret(ret.length - 1) + ret(ret.length - 2)
      if (temp >= n) {
        return ret.toList
      }
      ret += temp
    }
    ret.toList
  }

所以上面是我使用Scala生成Fibonacci序列到值n的代码。我想知道在Scala中是否有更优雅的方法可以做到这一点?

7 个答案:

答案 0 :(得分:76)

这更优雅:

val fibs: Stream[Int] = 0 #:: fibs.scanLeft(1)(_ + _)

使用Streams,您可以“获取”许多值,然后您可以将其转换为List:

scala> fibs take 10 toList
res42: List[Int] = List(0, 1, 1, 2, 3, 5, 8, 13, 21, 34)

更新:我写了一篇blog post,详细介绍了这个解决方案的工作原理,以及为什么你最终得到斐波纳契数列!

答案 1 :(得分:26)

定义Fibonacci序列有很多方法,但我最喜欢的是这个:

val fibs:Stream[Int] = 0 #:: 1 #:: (fibs zip fibs.tail).map{ t => t._1 + t._2 }

这会创建一个流,当您需要特定的Fibonacci数时,该流会被懒惰地评估。

编辑: 首先,正如Luigi Plinge指出的那样,开始时的“懒惰”是不必要的。 第二,去看看他的回答,他几乎只做了同样的事情。

答案 2 :(得分:5)

不像Streams那么优雅,不是懒惰,而是拖尾并处理BigInt(这也很容易用Luigis scanLeft做,但Tal的拉链也不行 - 也许只适合我)。

@tailrec 
def fib (cnt: Int, low: BigInt=0, high: BigInt=1, sofar: List[BigInt]=Nil): List[BigInt] = {
  if (cnt == 0) (low :: sofar).reverse else fib (cnt - 1, high, low + high, low :: sofar) }
  

阶&GT; fib(75)
  res135:列表[BigInt] =列表(0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765 ,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986,102325155,165580141,267914296,433494437,701408733,1344903170 ,1836311903,2971215073,4807526976,7778742049,12586269025,20365011074,32951280099,53316291173,86267571272,139583862445,225851433717,365435296162,591286729879,956722026041,1548008755920,2504730781961,4052739537881,6557470319842,10610209857723,17167680177565,27777890035288,44945570212853,72723460248141,117669030460994,190392490709135 ,308061521170129,498454011879264,806515533049393,1304969544928657,21148485077978050)

答案 3 :(得分:4)

我最喜欢的版本是:

def fibs(a: Int = 0, b: Int = 1): Stream[Int] = Stream.cons(a, fibs(b, a+b))

使用默认值,您只需拨打fibs()即可获得无限Stream

我认为尽管是一个班轮,但它的可读性很高。

如果您只想要第一个n,那么您可以take使用fibs() take n,如果您需要fibs() take n toList列表。

答案 4 :(得分:1)

这是在中间元组上再次使用* Stream * s的另一种方法:

scala> val fibs = Stream.iterate( (0,1) ) { case (a,b)=>(b,a+b)  }.map(_._1) 
fibs: scala.collection.immutable.Stream[Int] = Stream(0, ?)

scala> fibs take 10 toList
res68: List[Int] = List(0, 1, 1, 2, 3, 5, 8, 13, 21, 34)

答案 5 :(得分:0)

我觉得这个实现更加清晰:

def fibonacci: Stream[Int] = {
    def loop(a: Int, b: Int): Stream[Int] = (a + b) #:: loop(b, b + a)
    loop(0, 1)
}

答案 6 :(得分:0)

def fib:Stream[Int] ={
  def go(f0: Int, f1:Int): Stream[Int] = {
    Stream.cons(f0,go(f1,f0+f1))
  }
  go(0,1)
}