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でこれを行うためのよりエレガントな方法があるかどうか疑問に思っていますか?
フィボナッチ数列を定義する方法はたくさんありますが、私のお気に入りはこれです。
val fibs:Stream[Int] = 0 #:: 1 #:: (fibs Zip fibs.tail).map{ t => t._1 + t._2 }
これにより、特定のフィボナッチ数が必要なときに遅延評価されるストリームが作成されます。
編集:最初に、Luigi Plingeが指摘したように、最初の「怠惰な」は不要でした。第二に、彼の答えを見てください、彼はほとんど同じことをもっとエレガントにしただけです。
これはもう少しエレガントです:
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)
更新:私は ブログ投稿 を書きました。これは、このソリューションがどのように機能するか、そしてなぜフィボナッチ数列になるのかについてより詳細に説明しています!
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)
私のお気に入りのバージョンは次のとおりです。
_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
を使用できます。
中間タプルで* 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)
def fib:Stream[Int] ={
def go(f0: Int, f1:Int): Stream[Int] = {
Stream.cons(f0,go(f1,f0+f1))
}
go(0,1)
}
この実装の方が読みやすいと思います。
def fibonacci: Stream[Int] = {
def loop(a: Int, b: Int): Stream[Int] = (a + b) #:: loop(b, b + a)
loop(0, 1)
}