Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a finite iterator with contents being a result of an expression?

Tags:

scala

I'd like to create an Iterator that gets its next element by (repeatedly) evaluating an expression, and I want the expression to be able to return a certain value to terminate it.

The only thing I've found like this is Iterator.continually(), which seems to be infinite. It's important that the expression should not be evaluated until next() is called on the Iterator.

Is there a way to get this behaviour?

for example:

def getNext = {
  // some complicated code
  val next = ... // either a STOP value or a real value to be returned by the iterator
} 

val myIter = Iterator.continually(getNext) // want this to stop at some point
like image 892
Heinrich Schmetterling Avatar asked May 29 '11 00:05

Heinrich Schmetterling


2 Answers

Iterator.continually is usually combined with takeWhile:

var count = 0
def complexCompute(): Int = { count +=1; println("eval " + count); count }

val iter = Iterator.continually { complexCompute() }
iter.takeWhile(_ < 3).foreach(println)

Which prints:

eval 1
1
eval 2
2
eval 3

So if the condition that determines whether the computation should continue can be evaluated outside the computation then this works pretty well.

Basically I guess I'm saying Iterator.continually(getNext()).takeWhile(_ != certainValue) will achieve what you're trying to do. It's lazily evaluated.

like image 115
huynhjl Avatar answered Nov 16 '22 02:11

huynhjl


Have you looked at scala.collection.immutable.Stream? It's purpose it to create a sequence like object where the next element is lazily evaluated. It can be finite or infinite.

For example:

Welcome to Scala version 2.9.0.final (Java HotSpot(TM) Client VM, Java 1.6.0_24).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import collection.immutable._
import collection.immutable._

scala> def next(i: Int): Stream[Int] = Stream.cons(i*i, next(i*i))
next: (i: Int)scala.collection.immutable.Stream[Int]

scala> val stream = next(2)
stream: scala.collection.immutable.Stream[Int] = Stream(4, ?)

scala> stream.find(_ > 1000)
res0: Option[Int] = Some(65536)
like image 23
Synesso Avatar answered Nov 16 '22 04:11

Synesso