Поток вызывает OutOfMemoryError в Scala

Когда я использую Список, он работает правильно, но когда я создаю бесконечный поток

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 ответа

Похоже, вы пытаетесь создать тройки, в которых первый член больше второго. Для начала позвольте генерировать несколько таких пар:

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 не ограничено, я не понимаю, что вы хотите, чтобы программа выполняла. Просто рисование z из natNums превращает процессор в тостер:

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))

Обратите внимание, что мы начинаем с гипотенузы, ограничивая, таким образом, a и b. Кстати, вы могли бы сделать некоторые небольшие оптимизации, например, начать c с 5, a на 2 и b с a+1.


Это работает в 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 [?].

licensed under cc by-sa 3.0 with attribution.