Scala中的无限流

Scala中的无限流,scala,stream,Scala,Stream,假设我有一个函数,例如旧收藏夹 def factorial(n:Int) = (BigInt(1) /: (1 to n)) (_*_) 现在我想找到n的最大值,其中factorial(n)适合于一个长的函数。我可以 (1 to 100) takeWhile (factorial(_) <= Long.MaxValue) last 但是有更好的办法吗 (我也知道我可以递归地得到一个解决方案,但这不是我想要的。) 创建从1开始并递增1的流。这一切都在使用迭代器的解决方案中。 您还可以使用

假设我有一个函数,例如旧收藏夹

def factorial(n:Int) = (BigInt(1) /: (1 to n)) (_*_)
现在我想找到
n
的最大值,其中
factorial(n)
适合于一个长的函数。我可以

(1 to 100) takeWhile (factorial(_) <= Long.MaxValue) last
但是有更好的办法吗

(我也知道我可以递归地得到一个解决方案,但这不是我想要的。)

创建从1开始并递增1的流。这一切都在使用迭代器的解决方案中。

您还可以使用
迭代器
而不是
保留所有计算值的引用。因此,如果您计划只访问每个值一次,那么迭代器是一种更有效的方法。不过,迭代器的缺点是它的易变性

有一些非常方便的方法可以创建its上定义的
迭代器

编辑 不幸的是,据我所知,没有一种简短的(受库支持的)方法可以实现类似这样的目标

Stream.from(1) takeWhile (factorial(_) <= Long.MaxValue) last
-1
用于此特殊目的,但不是通用解决方案。但是使用pimp my library在
迭代器上实现
last
方法应该没有问题。问题是使用无限迭代器的最后一个元素可能会有问题。因此,它应该像
lastWith
集成
takeWhile
那样实现

使用
滑动
可以完成一个难看的解决方法,这是为
迭代器
实现的:

scala> Iterator.from(1).sliding(2).dropWhile(_.tail.head < 10).next.head
res12: Int = 9
scala>Iterator.from(1).滑动(2).dropWhile(u.tail.head<10).下一个.head
res12:Int=9

正如@ziggystar所指出的,
Streams
将以前计算的值列表保存在内存中,因此使用
迭代器是一个很大的改进

为了进一步改进答案,我认为“无限流”通常是基于预先计算的值来计算(或可以计算)的。如果是这种情况(在您的阶乘流中肯定是这样),我建议使用
Iterator.iterate

大致如下所示:

scala> val it = Iterator.iterate((1,BigInt(1))){case (i,f) => (i+1,f*(i+1))}
it: Iterator[(Int, scala.math.BigInt)] = non-empty iterator
val f : Stream[BigInt] = 1 #:: (Stream.from(1) zip f).map { case (x,y) => x * y }
println( "count: " + (f takeWhile (_<Long.MaxValue)).length )
然后,你可以做如下事情:

scala> it.find(_._2 >= Long.MaxValue).map(_._1).get - 1
res0: Int = 22
或者使用@ziggystar
滑动
解决方案

另一个容易想到的例子是斐波那契数:

scala> val it = Iterator.iterate((1,1)){case (a,b) => (b,a+b)}.map(_._1)
it: Iterator[Int] = non-empty iterator
在这些情况下,您的计算不是每次从头开始计算新元素,而是对每个新元素进行O(1)运算,这将进一步提高您的运行时间。

原始的“阶乘”函数不是最优的,因为阶乘每次都是从头开始计算的。使用备忘录的最简单/不可变实现如下所示:

scala> val it = Iterator.iterate((1,BigInt(1))){case (i,f) => (i+1,f*(i+1))}
it: Iterator[(Int, scala.math.BigInt)] = non-empty iterator
val f : Stream[BigInt] = 1 #:: (Stream.from(1) zip f).map { case (x,y) => x * y }
println( "count: " + (f takeWhile (_<Long.MaxValue)).length )
现在,答案可以这样计算:

scala> val it = Iterator.iterate((1,BigInt(1))){case (i,f) => (i+1,f*(i+1))}
it: Iterator[(Int, scala.math.BigInt)] = non-empty iterator
val f : Stream[BigInt] = 1 #:: (Stream.from(1) zip f).map { case (x,y) => x * y }
println( "count: " + (f takeWhile (_<Long.MaxValue)).length )

println(“count:”+(f takeWhile)(\up>以下变量不测试当前值,而是测试下一个整数,以便查找并返回最后一个有效数字:

Iterator.from(1).find(i => factorial(i+1) > Long.MaxValue).get

在这里使用
.get
是可以接受的,因为无限序列上的
find
永远不会返回
None

我想知道迭代器的等价物是
Stream
Stream
从2.13.0开始就不推荐使用。请改用
LazyList
。因此这将是
LazyList.from(1)