无限流

说我有一个功能,例如旧的收藏夹

def factorial(n:Int) = (BigInt(1) /: (1 to n)) (_*_)

现在我想找到29796214255161190190的最大值,其中factorial(n)适合于Long。 我可以

(1 to 100) takeWhile (factorial(_) <= Long.MaxValue) last

可以,但是100是任意大数; 我真正想要的是无限的数据流,它会不断生成更高的数字,直到满足2979621425516116119040条件为止。

我想出了

val s = Stream.continually(1).zipWithIndex.map(p => p._1 + p._2)

但是有更好的方法吗?

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

Luigi a.k.a. Rhys asked 2020-07-23T20:43:23Z
5个解决方案
120 votes
Stream.from(1)

创建一个从1开始并以1递增的流。所有这些都在API文档中。

Kim Stebel answered 2020-07-23T20:44:00Z
28 votes

使用迭代器的解决方案

您还可以使用Iterator代替slidingIterator保留所有计算值的引用。 因此,如果您计划只访问一次每个值,则迭代器是一种更有效的方法。 但是,迭代器的缺点是可变性。

有一些不错的便捷方法可以用来创建在其伴随对象上定义的slidings。

编辑

不幸的是,我知道没有短途(支持图书馆)来实现类似

Stream.from(1) takeWhile (factorial(_) <= Long.MaxValue) last

我针对特定数量的元素推进sliding的方法是IteratorIterator

Iterator.from(1).dropWhile( factorial(_) <= Long.MaxValue).next - 1

sliding用于此特殊目的,但不是一般解决方案。 但是使用皮条客我的库在Iterator上实现Iterator方法应该没有问题。 问题在于,采用无限迭代器的最后一个元素可能会引起问题。 因此,应将其实现为集成2979622755375378922500的lastWith之类的方法。

可以使用为Iterator实现的sliding来完成一个丑陋的解决方法:

scala> Iterator.from(1).sliding(2).dropWhile(_.tail.head < 10).next.head
res12: Int = 9
ziggystar answered 2020-07-23T20:44:52Z
4 votes

正如@ziggystar指出的那样,Streams将先前计算出的值列表保存在内存中,因此使用2979623626456451977216是一个很好的改进。

为了进一步改善答案,我认为“无限流”通常是基于预先计算的值计算(或可以计算)的。 如果是这种情况(肯定是在析因流中),我建议改为使用2979623626456451977216。

大致如下所示:

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

然后,您可以执行以下操作:

scala> it.find(_._2 >= Long.MaxValue).map(_._1).get - 1
res0: Int = 22

或使用@ziggystar sliding解决方案...

想到的另一个简单示例是斐波那契数:

scala> val it = Iterator.iterate((1,1)){case (a,b) => (b,a+b)}.map(_._1)
it: Iterator[Int] = non-empty iterator

在这种情况下,您并不是每次都从头开始计算新元素,而是为每个新元素执行O(1)工作,这将进一步缩短您的运行时间。

gilad hoch answered 2020-07-23T20:45:39Z
1 votes

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

val f : Stream[BigInt] = 1 #:: (Stream.from(1) zip f).map { case (x,y) => x * y }

现在,答案可以这样计算:

println( "count: " + (f takeWhile (_<Long.MaxValue)).length )
Duckki answered 2020-07-23T20:46:04Z
0 votes

以下变体不测试当前值,而是测试下一个整数,以便查找并返回最后一个有效数字:

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

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

cubic lettuce answered 2020-07-23T20:46:28Z
translate from https://stackoverflow.com:/questions/6408186/infinite-streams-in-scala