Scala: filter forcing the entire stream to be evaluated

The following code is called once from the method itself, called once inside the class constructor. When it starts as part of the UnitTest specifications, the test gets stuck, and a javaw process that quickly consumes more and more memory is generated.

private def placeMines( excludes: List[( Int, Int )] ) { def rndstream: Stream[( Int, Int )] = { def s: Stream[( Int, Int )] = ( Random.nextInt( ysize ), Random.nextInt( xsize ) ) #:: s s } def posPermitted( pos: ( Int, Int ) ): Boolean = { !excludes.contains( pos ) && fieldEmpty( pos._1, pos._2 ) } val positions = rndstream.filter( posPermitted ) positions.take( minecount ).foreach( x => grid( x._1 )( x._2 ) = MineField() ) } 

To find out what is happening, I commented on the last line with a side effect (the grid is a two-dimensional array) and replaced the filter predicate with different ones, including x => false and x => true. Interestingly, it ends in the true case, but continues to work forever with the false. An insert of some printlns showed that the predicate is called a hundred thousand times before I complete the java process.

I tried to reproduce the situation with the following code:

 import scala.util.Random import org.specs.SpecificationWithJUnit class foobar extends SpecificationWithJUnit { val x = 0xDead val y = 0xBeef bar(x, y) private def bar(x: Int, y: Int) = foo(x) private def foo(x: Int) = { def s: Stream[( Int, Int )] = { def p: Stream[( Int, Int )] = ( Random.nextInt( x ), Random.nextInt( y ) ) #:: p p } val fiveodd = s.filter( x => x._1 % 2 == 1 ) println( fiveodd.take( 5 ).toList ) } } 

However, this code works very well.

Looks for "scala stream filter endless", "scala stream filter filter" and "scala stream filter does not end" just picked up tutorials demonstrating the use of streams that were basically identical to my code,

+4
source share
1 answer

I think something is wrong with your filter function. Stream.filter tries to find the first matching value, and if it is not, it will search forever.

Take an example stream and call

 s.filter(_ => false) 

This will not be returned, so this should be your filter function.

+3
source

All Articles