如何在 scala 中使用滑动流获取斐波那契数



Stream 文档中有一个很好的例子,它得到了斐波那契数。

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

我想通过使用滑动来实现这一点,所以我尝试了以下内容。

val test = 0 #:: 1 #:: Stream.empty
test.sliding(2).map(_.sum).toStream

最后一行正确获取 Stream(1, ?) 但是当我按如下方式将其连接到上面时,当我尝试获取第 3 个成员时,我收到一个错误(可能是堆栈溢出,我看不到确切的错误消息,因为它太长了)。

val fibs2:Stream[Int] = 0 #:: 1 #:: fibs2.sliding(2).map(_.sum).toStream

如果我按如下方式给出 3 个数字,它会计算前两个数字的总和。但这不是斐波那契数。

val fibs3:Stream[Int] = 0 #:: 0 #:: 1 #:: fibs3.sliding(2).map(_.sum).toStream

任何想法或帮助将不胜感激。

更新

  • 我怀疑错误的原因是滑动方法返回迭代器,它需要使用hasNext方法知道下一个值是否可用
  • 滑动方法应计算如果给出第一个播种者,则先前n个数字的任何总和,称为Tribonacci(n = 3),tetranacci(n = 4)等。

问题似乎是GroupedIterator(由 sliding 返回)过于急切。在创建每个滑动窗口时,它会强制当前窗口之后的下一个元素。

下面是一个简单的示例:

import scala.util.Try
def bad[T]: Stream[T] = throw new RuntimeException("Don't peek!")
// Should be able to view group of first 2 elements without error,
// but sliding and grouped both read the 3rd element
def testA: Stream[Int] = 1 #:: 2 #:: bad
Try { testA.sliding(2).next }
// res0: scala.util.Try[scala.collection.immutable.Stream[Int]] = Failure(java.lang.RuntimeException: Don't peek!)
Try { testA.grouped(2).next }
// res1: scala.util.Try[scala.collection.immutable.Stream[Int]] = Failure(java.lang.RuntimeException: Don't peek!)
// Adding an extra element before the bad entry gives
// sufficient padding for a sliding window of 2
def testB: Stream[Int] = 1 #:: 2 #:: 3 #:: bad
Try { testB.sliding(2).next }
// res2: scala.util.Try[scala.collection.immutable.Stream[Int]] = Success(Stream(1, ?))
Try { testB.grouped(2).next }
// res3: scala.util.Try[scala.collection.immutable.Stream[Int]] = Success(Stream(1, ?))

您可以使用scanLeft代替sliding

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

scan函数有点像fold,但产生所有的中间结果。所以你得到的是这个:

  • 0
  • 1 = 1
  • 0 + 1 = 1
  • 1 + 1 = 2
  • 1 + 2 = 3
  • 2 + 3 = 5

道文的明确解释表明滑动方法不能解决问题。我发现了另一种计算高阶斐波那契数的方法。

/* make a Stream of Stream of integer 
input - Stream(0, 1)
output - Stream(0, 1), Stream(1, 1), Stream(1, 2), Stream(2, 3), ... 
*/
def appendSum(initial:Stream[Int]):Stream[Stream[Int]] = 
  Stream.iterate(initial)(s => s.tail :+ s.sum)
/* fibonacci number of higher order is original Stream + new Stream's last member */
def nbonacci(n:Int) = { 
    val inits = Stream.continually(0).take(n-1) :+ 1
    inits.append(appendSum(inits).tail.map(_.last)) 
}
/* print out first 20 members of fibonacci, tribonacci, tetrabonacci numbers */
(2 to 4).foreach(n => {println(s"$n -----"); nbonacci(n).take(20).foreach(println(_))})

如果滑动返回的流,它会更干净,也许会更快。

相关内容

  • 没有找到相关文章

最新更新