在Scala中生成一系列Fibonacci数

nob*_*ody 20 scala list-comprehension sequence 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中是否有更优雅的方法可以做到这一点?

Lui*_*hys 83

这有点优雅:

val fibs: Stream[Int] = 0 #:: fibs.scanLeft(1)(_ + _)
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • @HunterMcMillen实际上取决于你定义的地方.如果在"对象"或REPL的顶层,则不会.如果它在一个方法中,那么你确实需要`lazy`. (10认同)
  • @LuigiPlinge这不是一个前瞻性的参考?仅在我应用`lazy`关键字时才有效. (7认同)
  • @DCKing这是由于范围.类的成员可以引用任何其他成员,它们定义的顺序无关紧要.但在方法中,您只能引用上面定义的内容. (5认同)
  • @LuigiPlinge我理解你的观点,但我想用scan使用这个斐波那契序列学习不可变的样式编程. (2认同)

Tal*_*man 27

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

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

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

编辑:首先,正如Luigi Plinge指出的那样,开始时的"懒惰"是不必要的.第二,去看看他的答案,他几乎只做了同样的事情,更优雅.

  • 不需要是一个懒惰的val; 懒惰只是意味着它没有急切地评估你已经作为文字给出的第一个词0 (2认同)

use*_*own 6

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

scala> 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,7711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986,102325155,165580141,267914296 ,433494437,701408733,1134903170,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,2114885077978050)

  • 类似:`def fib(n:Int,s:List [BigInt] = List(1,0)):List [BigInt] = if(n &lt;= 2)s.reverse else fib(n-1,s(0 )+ s(1):: s)` (2认同)

小智 5

我最喜欢的版本是:

def fibs(a: Int = 0, b: Int = 1): Stream[Int] = Stream.cons(a, fibs(b, a+b))
Run Code Online (Sandbox Code Playgroud)

使用默认值,您可以调用fibs()并获取infinite Stream

我也认为,尽管只有一个衬里,但它仍具有很高的可读性。

如果只想要第一个,n则可以使用takelike fibs() take n,如果需要它作为列表fibs() take n toList