Co muszę zrobić, aby móc zwrócić Iterator z metody/klasy? Jak dodać tę cechę do klasy?Jak zwrócisz Iterator w Scali?
Odpowiedz
można rozszerzyć Iterator, które będą wymagać wdrożenia next
i hasNext
metody:
class MyAnswer extends Iterator[Int] {
def hasNext = true
def next = 42
}
Ale, dostaniesz większą elastyczność jeśli przedłużyć Iterable, który wymaga wdrożenia elements
(lub iterator
w 2,8):
class MyAnswer extends Iterable[Int] {
def iterator = new Iterator[Int] {
def hasNext = true
def next = 42
}
}
wspólne idiom wydaje się, aby odsłonić iterator do jakiejś prywatnej kolekcji, na przykład:
class MyStooges extends Iterable[String] {
private val stooges = List("Moe", "Larry", "Curly")
def iterator = stooges.iterator
}
na sposób, po prostu yield:
def odd(from: Int, to: Int): List[Int] =
for (i <- List.range(from, to) if i % 2 == 1) yield i
Prawidłowo, ale ... przykład kodu faktycznie nie odpowiada na pytanie. Po prostu zamień oba wystąpienia "List" na "Iterator" i działa idealnie! –
Te dwie odpowiedzi miał pomocy z poniższych stanowisk i dzięki @Dima.
How do I implement an iterator for an existing singly linked list?
why does this iterable implementation produce a stackoverflow?
Załóżmy, że masz listę klasy powiązane. Wymagane jest wydrukowanie wszystkich elementów na liście.
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)
[email protected]: Unit =()
Teraz pozwala na wdrożenie iteratora dla tej klasy.
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
W implementacji iteratora, gdy ptr osiągnie koniec, może nie wrócić z powrotem. Iterowalna implementacja rozwiązuje to.
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
Nie ma sposobu na wysyłanie prywatnych wiadomości, ale chciałbym zadać pytanie: czy mógłbyś wskazać mi na użycie wspólnego idiomu, o którym wspomniałeś? Jeśli nie, jakie może być przydatne? Dlaczego nie po prostu zwrócić listę? Czy ten idiom nie byłby mniej skuteczny? (Również: widziałem tę sztuczkę Iterable [A] "kilka razy" i wydaje się, że jest to jeden z najszybszych sposobów na stworzenie czegoś podobnego do kolekcji, czy są jakieś "alternatywy" do tego podejścia? Tak, ponieważ Iterator daje mało informacji, więc metod nie można zoptymalizować dobrze, co jeśli wiedziałbym, że mój pseudo coll zwraca zamówione lub ma szybki losowy dostęp) – Aktau