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
我想知道迭代器的等价物是StreamStream
从2.13.0开始就不推荐使用。请改用LazyList
。因此这将是LazyList.from(1)
。