Scala堆大小异常中的Euler 23

时间:2012-12-05 12:08:40

标签: algorithm scala stream

我想解决Scala中的this问题。 我的代码:

def dividers(n: Int) =
  (1 until n) filter (x => n%x == 0)

def sumOfDividers(n: Int) = dividers(n).sum

val abNumbers = (1 to 28123) filter (x => sumOfDividers(x) > x)

我的解决方案的下一步是制作一些序列,其中包含来自abNumbers序列的所有可能的丰富数字。我已尝试使用增强的for循环执行此操作,但它会在运行时抛出Java Heap Exception。如何将所有这些总和放入Stream结构中?

2 个答案:

答案 0 :(得分:2)

在范围上使用toStream方法:

val abNumbers = ((1 to 28123) toStream).filter (x => sumOfDividers(x) > x)

abNumbers: scala.collection.immutable.Stream[Int] = Stream(12, ?)

或者我错过了什么?

答案 1 :(得分:0)

Streams与无限序列很好地配合使用。但是,在这里你知道你的界限;你只是想避免作为函数式编程的副产品而出现的所有中间集合。 (旁注:即使在适度的硬件上,Euler 23也应该在挥霍无度的强力中使用;只是你的堆可能太小了吗?)

如果主要关注的是内存,请考虑使用视图。像Streams一样,Scala中的视图很懒惰。但语义不同。考虑一下:

(1 to 100000) map (_+1) filter (x => x % 2 == 0) map (x => x*x) 

这里的意图是函数组合,但这会在途中创建几个中间集合:每个mapfilter将返回一个新的,可能具有同等大小的集合。 观看次数是获得性能(通过内存效率)和组合性的一种解决方案:您只需创建“起始”集合作为视图:

(1 to 100000 view) map (_+1) filter (x => x % 2 == 0) map (x => x*x) 

哪会快速返回SeqView而不是通常的Seq - 当视图实际被强制时,您的转换(在mapfilter中)有效地完成一个而不是不同的中间集合。可以认为它们类似于SQL中对表的视图。根据您计划解决欧拉问题23的方式,视图可能会有所帮助。它们只是在Scala中利用懒惰的方法之一 - 请参阅这篇文章,了解视图,流和迭代器之间的差异:Stream vs Views vs Iterators