How do you return an Iterator in Scala?

后端 未结 3 1388
执念已碎
执念已碎 2020-12-30 00:39

What must I do in order to be able to return an Iterator from a method/class ? How would one add that trait to a class?

相关标签:
3条回答
  • 2020-12-30 00:59

    For a method, just yield:

    def odd(from: Int, to: Int): List[Int] = 
      for (i <- List.range(from, to) if i % 2 == 1) yield i
    
    0 讨论(0)
  • 2020-12-30 01:00

    You can extend Iterator, which will require that you implement the next and hasNext methods:

      class MyAnswer extends Iterator[Int] {
        def hasNext = true
        def next = 42
      }
    

    But, you will get more flexibility if you extend Iterable, which requires you implement elements (or iterator in 2.8):

      class MyAnswer extends Iterable[Int] {
        def iterator = new Iterator[Int] {
          def hasNext = true
          def next = 42
        }
      }
    

    A common idiom seems to be to expose an iterator to some private collection, like this:

      class MyStooges extends Iterable[String] {
        private val stooges = List("Moe", "Larry", "Curly")
        def iterator = stooges.iterator
      }
    
    0 讨论(0)
  • 2020-12-30 01:21

    These two answers had help from the posts below and thanks @Dima.

    • How do I implement an iterator for an existing singly linked list?

    • why does this iterable implementation produce a stackoverflow?

    Lets assume you have a class linked list. And the requirement is to print all the elements in the list.

    trait LinkedList {
      def nodeValue: Int
      def tailList: LinkedList
    }
    
    class Node(val nodeValue: Int, val tailList: LinkedList) extends LinkedList
    
    object Nil extends LinkedList {
      def nodeValue = throw new IllegalAccessException("head of Nil")
      def tailList = throw new IllegalAccessException("tail of Nil")
    }
    
    val singleLinkedList = new Node(1,Nil)
    val chainedLinkedList = new Node(2,singleLinkedList)
    print(chainedLinkedList)
    A$A44$A$A44$Node@7b7a2c78res0: Unit = ()
    

    Now Lets implement iterator to this class.

    trait LinkedList extends Iterator[Int]{
      def nodeValue: Int
      def tailList: LinkedList
    }
    
    class Node(val nodeValue: Int, val tailList: LinkedList) extends LinkedList {
      var ptr: LinkedList = this
    
      //The following two are mandatory for extending Iterator
      override def hasNext: Boolean = ptr match { case Nil => false; case _=> true}
    
      override def next(): Int = {
        val result = ptr.nodeValue
        ptr = ptr.tailList
        result
      }
    }
    
    object Nil extends LinkedList {
      def nodeValue = throw new IllegalAccessException("head of Nil")
      def tailList = throw new IllegalAccessException("tail of Nil")
    
      //The following two are mandatory for extending Iterator
      override def hasNext: Boolean = false
      override def next(): Int = throw new IllegalAccessException("next of Nil")
    }
    
    val singleLinkedList = new Node(1,Nil)
    val chainedLinkedList = new Node(2,singleLinkedList)
    
    //Printing this first Time
    chainedLinkedList.foreach(println)
    //Prints 2 1
    
    //Printing second Time
    chainedLinkedList.foreach(println)
    //No output
    

    In the iterator implementation, once ptr reached the end, it could did not advance back. Iterable implementation solves this.

    trait LinkedList extends Iterable[Int]{
      val nodeValue: Int
      val tailList: LinkedList
      override def toString(): String = this.mkString(" -> ")
    }
    
    class Node(val nodeValue: Int, val tailList: LinkedList) extends LinkedList {
    
      override def iterator: Iterator[Int] = Iterator
        .iterate(this: LinkedList)(_.tailList)
        .takeWhile(_ != Nil)
        .map(_.nodeValue)
    }
    
    object Nil extends LinkedList {
      lazy val nodeValue= throw new IllegalAccessException("head of Nil")
      lazy val tailList = throw new IllegalAccessException("tail of Nil")
    
      override def iterator: Iterator[Int] = Iterator.empty
    }
    
    val singleLinkedList = new Node(1,Nil)
    val chainedLinkedList = new Node(2,singleLinkedList)
    
    //Printing this first Time
    chainedLinkedList.foreach(println)
    Output 2 -> 1
    chainedLinkedList.foreach(println)
    Output 2 -> 1
    
    0 讨论(0)
提交回复
热议问题