Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to use 'yield' to generate 'Iterator' instead of a list in Scala?

Is it possible to use yield as an iterator without evaluation of every value?

It is a common task when it is easy to implement complex list generation, and then you need to convert it into Iterator, because you don't need some results...

like image 957
yura Avatar asked Dec 24 '10 09:12

yura


People also ask

What is the use of yield in Scala?

yield keyword will returns a result after completing of loop iterations. The for loop used buffer internally to store iterated result and when finishing all iterations it yields the ultimate result from that buffer. It doesn't work like imperative loop.

How do you create an iterator in Scala?

Creates two new iterators that both iterate over the same elements as this iterator (in the same order). Returns true if the given predicate p holds for some of the values produced by this iterator, otherwise false. Returns an iterator over all the elements of this iterator that satisfy the predicate p.

What is true about iterators in Scala?

An iterator is not a collection, but rather a way to access the elements of a collection one by one. The two basic operations on an iterator it are next and hasNext . A call to it. next() will return the next element of the iterator and advance the state of the iterator.

Is Scala iterator lazy?

Unlike operations directly on a concrete collection like List , operations on Iterator are lazy. A lazy operation does not immediately compute all of its results.


1 Answers

Sure. Actually, there are three options for non-strictness, which I list below. For the examples, assume:

val list = List.range(1, 10) def compute(n: Int) = {     println("Computing "+n)     n * 2 } 
  1. Stream. A Stream is a lazily evaluated list. It will compute values on demand, but it will not recompute values once they have been computed. It is most useful if you'll reuse parts of the stream many times. For example, running the code below will print "Computing 1", "Computing 2" and "Computing 3", one time each.

    val stream = for (n <- list.toStream) yield compute(n) val third = stream(2) println("%d %d" format (third, stream(2))) 
  2. A view. A view is a composition of operations over a base collection. When examining a view, each element examined is computed on-demand. It is most useful if you'll randomly access the view, but will never look but at a small part of it. For example, running the code below will print "Computing 3" two times, and nothing else (well, besides the result).

    val view = for (n <- list.view) yield compute(n) val third = view(2) println("%d %d" format (third, view(2))) 
  3. Iterator. An Iterator is something that is used to lazily walk through a collection. One can think of it as a "one-shot" collection, so to speak. It will neither recompute nor store any elements -- once an element has been "computed", it cannot be used again. It is a bit more tricky to use because of that, but it is the most efficient one given these constraints. For example, the following example needs to be different, because Iterator does not support indexed access (and view would perform badly if written this way), and the code below prints "Computing 1", "Computing 2", "Computing 3", "Computing 4", "Computing 5" and "Computing 6". Also, it prints two different numbers at the end.

    val iterator = for (n <- list.iterator) yield compute(n) val third = iterator.drop(2).next println("%d %d" format (third, iterator.drop(2).next)) 
like image 187
Daniel C. Sobral Avatar answered Sep 18 '22 15:09

Daniel C. Sobral