Stream导致Scala中的OutOfMemoryError

时间:2014-12-25 21:14:38

标签: scala stream

当我使用List时,它可以正常工作,但是当我创建一个无限的流

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)我遇到了同样的问题 请帮忙。提前谢谢!

2 个答案:

答案 0 :(得分:2)

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

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。顺便说一句,你可以进行一些小的优化,例如在5开始c,在{2}开始a,在b开始a+1

答案 1 :(得分:0)

这适用于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 [?]子类的类型。