web-dev-qa-db-ja.com

Scala)でフィボナッチ数のシーケンスを生成します


  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から値nまで)を使用してフィボナッチ数列を生成するコードです。Scalaでこれを行うためのよりエレガントな方法があるかどうか疑問に思っていますか?

21
nobody

フィボナッチ数列を定義する方法はたくさんありますが、私のお気に入りはこれです。

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

これにより、特定のフィボナッチ数が必要なときに遅延評価されるストリームが作成されます。

編集:最初に、Luigi Plingeが指摘したように、最初の「怠惰な」は不要でした。第二に、彼の答えを見てください、彼はほとんど同じことをもっとエレガントにしただけです。

30
Tal Pressman

これはもう少しエレガントです:

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

Streamsを使用すると、いくつかの値を「取得」して、リストに変換できます。

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

更新:私は ブログ投稿 を書きました。これは、このソリューションがどのように機能するか、そしてなぜフィボナッチ数列になるのかについてより詳細に説明しています!

87
Luigi Plinge

Streamsほどエレガントではなく、怠惰ではありませんが、末尾再帰でBigIntを処理します(これはLuigis scanLeftでも簡単に実行できますが、Tal's Zipではそうではありません-おそらく私だけです)。

@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) }

scala> fib(75)
res135:List [BigInt] = List(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、102334155、165580141、267914296 433494437、701408733、1134903170、1836311903、2971215073、4807526976、7778742049、12586269025、20365011074、32951280099、53316291173、86267571272、139583862445、225851433717、365435296162、591286729879、956722026041、154800875920、25047 72723460248141、117669030460994、190392490709135、308061521170129、498454011879264、806515533049393、1304969544928657、2111485077978050)

6
user unknown

私のお気に入りのバージョンは次のとおりです。

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

デフォルト値では、fibs()を呼び出すだけで、無限のStreamを取得できます。

また、ワンライナーでありながら読みやすいと思います。

最初のnが必要な場合は、fibs() take nのようにtakeを使用でき、リストとして必要な場合はfibs() take n toListを使用できます。

5
dvdnglnd

中間タプルで* 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)
1
dimitrisli
def fib:Stream[Int] ={
  def go(f0: Int, f1:Int): Stream[Int] = {
    Stream.cons(f0,go(f1,f0+f1))
  }
  go(0,1)
}
0

この実装の方が読みやすいと思います。

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