【问题标题】:Euler 23 in Scala Heap Size ExceptionScala 堆大小异常中的 Euler 23
【发布时间】:2012-11-23 06:16:37
【问题描述】:

我想在 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 结构中?

【问题讨论】:

  • 我假设 Java Heap Exception 是 OutOfMemoryException。但即使给进程 2Mb 的内存来使用,它也能成功完成,不管有没有流。
  • @DenisTulskiy 确实 - 也许我们想看看 OP 的“增强的 for 循环”?

标签: algorithm scala stream


【解决方案1】:

在范围上使用 toStream 方法:

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

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

还是我错过了什么?

【讨论】:

  • @senia 为什么?可以扩展一下吗?
  • 对 Stream 的引用是对其第一个元素的引用。 GC 在这个引用还活着的时候是无能为力的。
  • @senia 我不明白?而使用 var 会改变这一点?
  • @senia 但是你正在定义一个方法。每次你引用它时,它都会创建一个新的 Stream。这可能不是你想要的。
  • @senia,OP 明确表示(对我而言)他不会打电话给 abNumbers.sumabNumbers.drop。不管abNumbersdef 还是valabNumbers.foreach 都不是一个非常可行的想法 :-)
【解决方案2】:

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

如果您主要关心的是内存,请考虑使用 views。像 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-28
    • 2010-11-29
    • 2021-04-07
    • 1970-01-01
    • 2014-10-14
    • 2013-03-24
    相关资源
    最近更新 更多