【问题标题】:Stream causes OutOfMemoryError in ScalaStream 在 Scala 中导致 OutOfMemoryError
【发布时间】:2014-12-25 21:14:38
【问题描述】:

当我使用列表时,它可以正常工作,但是当我创建无限流时

def foo = {
    val s = Stream.from(1)
    s.flatMap(x =>
                s.flatMap(y =>
                    s.flatMap(z => f(x, y, z))))
}

我在调用时遇到 java.lang.OutOfMemoryError

foo.take(10)

关于 f

    def f(x: Int, y: Int, z: Int) = {
       if(Math.pow(x, 2) + Math.pow(y, 2) == Math.pow(z, 2) )
       else None
    }

最初,我认为只有当我为这 10 个元素调用它时才会评估它,但我知道我不确定。我遇到了与Iterator.from(1) 相同的问题 请提供任何帮助。提前谢谢!

【问题讨论】:

  • 如何在流中的每个元素上进行平面映射。它的无限!您将耗尽内存。你到底想做什么?
  • 你的代码对我有用。请发布您正在使用的确切代码,包括f 的定义。注意foo.take(10) 返回一个 Stream,所以我们还需要知道你在用这个值做什么
  • 我更新了我的问题。返回的流是我所期望的。谢谢保罗
  • @OK,所以失败了,而只返回 Some((x,y,z)) 的 f 没有。所以这是你对 x > y 的使用,它强制对 Stream 进行评估。
  • 不评价怎么办?有什么方法可以在这里使用惰性吗?非常感谢保罗

标签: scala stream


【解决方案1】:

看起来您正在尝试生成第一个成员大于第二个成员的三元组。首先,让我们生成一些这样的对:

scala> def natNums = Iterator from 1
natNums: Iterator[Int]

scala> def foo = for { x <- natNums; y <- 1 until x } yield (x,y)
foo: Iterator[(Int, Int)]

scala> (foo take 15).toList
res4: List[(Int, Int)] = List((2,1), (3,1), (3,2), (4,1), (4,2), (4,3), (5,1), (5,2), (5,3), (5,4), (6,1), (6,2), (6,3), (6,4), (6,5))

我走对了吗?

好的,现在您想在元组中添加第三个成员。好吧,如果我们同样将 z 限制为小于 y,它就可以正常工作:

scala> def foo = for { x <- natNums; y <- 1 until x; z <- 1 until y } yield (x,y,z)
foo: Iterator[(Int, Int, Int)]

scala> (foo take 15).toList
res1: List[(Int, Int, Int)] = List((3,2,1), (4,2,1), (4,3,1), (4,3,2), (5,2,1), (5,3,1), (5,3,2), (5,4,1), (5,4,2), (5,4,3), (6,2,1), (6,3,1), (6,3,2), (6,4,1), (6,4,2))

但如果 z 不受约束,我不明白你想让程序做什么。只需从 natNums 中绘制 z 即可将 CPU 变成烤面包机:

scala> def foo = for { x <- natNums; y <- 1 until x; z <- natNums } yield (x,y,z)
foo: Iterator[(Int, Int, Int)]

scala> (foo take 15).toList
^C

你能给我们你期望的输出吗?

更新:啊!毕达哥拉斯三元组——多么有趣!

这是一个简单的生成器,我将其称为“原始”毕达哥拉斯三元组,因为它包含需要过滤掉的倍数。例如,(6,8,10) 不应算作毕达哥拉斯三元组,因为它是 (3,4,5) 的倍数。我会把它留给你,因为我认为阻碍你的只是首先生成数字的部分。如果需要,请随时在另一个 StackOverflow 问题中寻求帮助。

scala> def rawPythagTriples =
   for { c <- Iterator from 1; a <- 1 until c; b <- a until c if a*a + b*b == c*c }
     yield (a,b,c)
rawPythagTriples: Iterator[(Int, Int, Int)]

scala> (rawPythagTriples take 10).toList
res2: List[(Int, Int, Int)] = List((3,4,5), (6,8,10), (5,12,13), (9,12,15), (8,15,17), (12,16,20), (7,24,25), (15,20,25), (10,24,26), (20,21,29))

请注意,我们从斜边开始,因此限制了 ab。顺便说一句,您可以进行一些小的优化,例如从 c 在 5、a 在 2 和 ba+1 开始。

【讨论】:

  • 谢谢 AmigoNico。我期望的输出是毕达哥拉斯三元组。很抱歉我没有从一开始就澄清这一点。
【解决方案2】:

这适用于 REPL:

def foo = {
  val s = Stream.from(1)
  s.flatMap(x =>
    s.flatMap(y =>
      s.flatMap(z => List(x,y,z))))
}

scala> foo.take(15) mkString ", "
res24: String = 1, 1, 1, 1, 1, 2, 1, 1, 3, 1, 1, 4, 1, 1, 5

您的 f(x,y,z) 必须返回一个扩展 GenTraversableOnce[?] 子类的类型。

【讨论】:

  • 是的,确实如此,但更新后的问题中f 的定义没有。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-18
  • 2012-06-06
  • 1970-01-01
  • 2012-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多