Heinrich Schmetterling
Heinrich Schmetterling

Reputation: 6884

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

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

Upvotes: 17

Views: 13286

Answers (2)

huynhjl
huynhjl

Reputation: 41646

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.

Upvotes: 29

Synesso
Synesso

Reputation: 38978

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)

Upvotes: 6

Related Questions