Как вы возвращаете итератор в Scala? - PullRequest
21 голосов
/ 25 января 2010

Что я должен сделать, чтобы иметь возможность возвращать итератор из метода / класса? Как добавить эту черту в класс?

Ответы [ 3 ]

32 голосов
/ 25 января 2010

Вы можете расширить Итератор , что потребует от вас реализации методов next и hasNext:

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

Но вы получите больше гибкости, если расширите Итерируемый , для чего необходимо реализовать elements (или iterator в 2.8):

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

Обычной идиомой, по-видимому, является выставление итератора в какую-то частную коллекцию, например:

  class MyStooges extends Iterable[String] {
    private val stooges = List("Moe", "Larry", "Curly")
    def iterator = stooges.iterator
  }
9 голосов
/ 26 января 2010

Для метода просто yield :

def odd(from: Int, to: Int): List[Int] = 
  for (i <- List.range(from, to) if i % 2 == 1) yield i
1 голос
/ 03 июля 2017

Этим двум ответам помогли посты ниже и спасибо @ Дима.

Предположим, у вас есть связанный список классов. И требование состоит в том, чтобы напечатать все элементы в списке.

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 = ()

Теперь давайте реализуем итератор для этого класса.

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

В реализации итератора, когда ptr достиг конца, он не смог продвинуться назад. Итеративная реализация решает это.

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
...