Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to program an iterator in scala without using a mutable variable?

I want to implement the iterator trait but in the functional way, ie, without using a var. How to do that?

Suppose I have an external library where I get some elements by calling a function getNextElements(numOfElements: Int):Array[String] and I want to implement an Iterator using that function but without using a variable indicating the "current" array (in my case, the var buffer). How can I implement that in the functional way?

class MyIterator[T](fillBuffer: Int => Array[T]) extends Iterator[T] {
    var buffer: List[T] = fillBuffer(10).toList

    override def hasNext(): Boolean = {
        if (buffer.isEmpty) buffer = fillBuffer(10).toList
        buffer.nonEmpty
    }

    override def next(): T = {
        if (!hasNext()) throw new NoSuchElementException()

        val elem: T = buffer.head
        buffer = buffer.tail
        elem
    }
}

class Main extends App {
    def getNextElements(num: Int): Array[String] = ???

    val iterator = new MyIterator[String](getNextElements)

    iterator.foreach(println)
}
like image 695
Heitor Barbieri Avatar asked Nov 18 '25 14:11

Heitor Barbieri


1 Answers

Iterators are mutable, at least without an interface that also returns a state variable, so you can't in general implement the interface directly without some sort of mutation.

That being said, there are some very useful functions in the Iterator companion object that let you hide the mutation, and make the implementation cleaner. I would implement yours something like:

Iterator.continually(getNextElements(10)).flatten

This calls getNextElements(10) whenever it needs to fill the buffer. The flatten changes it from an Iterator[Array[A]] to an Iterator[A].

Note this returns an infinite iterator. Your question didn't say anything about detecting the end of your source elements, but I would usually implement that using takeWhile. For example, if getNextElements returns an empty array when there are no more elements, you can do:

 Iterator.continually(getNextElements(10)).takeWhile(!_.isEmpty).flatten
like image 50
Karl Bielefeldt Avatar answered Nov 21 '25 04:11

Karl Bielefeldt



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!