Frage

Ich möchte den Iterator erweitern, um eine neue Methode zu erstellen takeWhileInclusive, die wie wie takeWhile Fügen Sie aber das letzte Element ein.

Mein Problem ist, was die beste Praxis ist, um den Iterator zu erweitern, um einen neuen Iterator zurückzugeben, den ich gerne faul werden möchte. Ich komme aus einem C# -Hintergrund, den ich normal benutze IEnumerable und benutze die yield Schlüsselwort, aber eine solche Option scheint in Scala nicht zu existieren.

Zum Beispiel könnte ich haben

List(0,1,2,3,4,5,6,7).iterator.map(complex time consuming algorithm).takeWhileInclusive(_ < 6)

Also in diesem Fall die takeWhileInclusive Hätte das Prädikat auf den Werten nur auflösen, bis ich ein Ergebnis von mehr als 6 erhalte, und es wird dieses erste Ergebnis enthalten

Bisher habe ich:

object ImplicitIterator {
  implicit def extendIterator(i : Iterator[Any]) = new IteratorExtension(i)
}

class IteratorExtension[T <: Any](i : Iterator[T]) {
  def takeWhileInclusive(predicate:(T) => Boolean) = ?
}
War es hilfreich?

Lösung

Dies ist ein Fall, in dem ich die veränderliche Lösung überlegen finde:

class InclusiveIterator[A](ia: Iterator[A]) {
  def takeWhileInclusive(p: A => Boolean) = {
    var done = false
    val p2 = (a: A) => !done && { if (!p(a)) done=true; true }
    ia.takeWhile(p2)
  }
}
implicit def iterator_can_include[A](ia: Iterator[A]) = new InclusiveIterator(ia)

Andere Tipps

Du kannst den ... benutzen span Methode von Iterator Um das ziemlich sauber zu tun:

class IteratorExtension[A](i : Iterator[A]) {
  def takeWhileInclusive(p: A => Boolean) = {
    val (a, b) = i.span(p)
    a ++ (if (b.hasNext) Some(b.next) else None)
  }
}

object ImplicitIterator {
  implicit def extendIterator[A](i : Iterator[A]) = new IteratorExtension(i)
}

import ImplicitIterator._

Jetzt (0 until 10).toIterator.takeWhileInclusive(_ < 4).toList gibt List(0, 1, 2, 3, 4), zum Beispiel.

Im Folgenden muss Scalaz bekommen fold auf einem Tupel (A, B)

scala> implicit def Iterator_Is_TWI[A](itr: Iterator[A]) = new { 
     | def takeWhileIncl(p: A => Boolean) 
     |   = itr span p fold (_ ++ _.toStream.headOption)
     | }
Iterator_Is_TWI: [A](itr: Iterator[A])java.lang.Object{def takeWhileIncl(p: A => Boolean): Iterator[A]}

Hier ist es bei der Arbeit:

scala> List(1, 2, 3, 4, 5).iterator takeWhileIncl (_ < 4)
res0: Iterator[Int] = non-empty iterator

scala> res0.toList
res1: List[Int] = List(1, 2, 3, 4)

Sie können Ihre eigene Falten über ein Paar wie dieses rollen:

scala> implicit def Pair_Is_Foldable[A, B](pair: (A, B)) = new { 
    |    def fold[C](f: (A, B) => C): C = f.tupled(pair) 
    |  } 
Pair_Is_Foldable: [A, B](pair: (A, B))java.lang.Object{def fold[C](f: (A, B) => C): C}
class IteratorExtension[T](i : Iterator[T]) {
  def takeWhileInclusive(predicate:(T) => Boolean) = new Iterator[T] {
    val it = i
    var isLastRead = false

    def hasNext = it.hasNext && !isLastRead
    def next = {
      val res = it.next
      isLastRead = !predicate(res)
      res
    }
  }
}

Und es gibt einen Fehler in Ihrem impliziten. Hier ist es behoben:

object ImplicitIterator {
  implicit def extendIterator[T](i : Iterator[T]) = new IteratorExtension(i)
}
scala> List(0,1,2,3,4,5,6,7).toStream.filter (_ < 6).take(2)
res8: scala.collection.immutable.Stream[Int] = Stream(0, ?)

scala> res8.toList 
res9: List[Int] = List(0, 1)

Nach Ihrem Update:

scala> def timeConsumeDummy (n: Int): Int = {
     | println ("Time flies like an arrow ...") 
     | n }
timeConsumeDummy: (n: Int)Int

scala> List(0,1,2,3,4,5,6,7).toStream.filter (x => timeConsumeDummy (x) < 6) 
Time flies like an arrow ...
res14: scala.collection.immutable.Stream[Int] = Stream(0, ?)

scala> res14.take (4).toList 
Time flies like an arrow ...
Time flies like an arrow ...
Time flies like an arrow ...
res15: List[Int] = List(0, 1, 2, 3)

Die Zeitspanne wird 4 -mal bezeichnet. Vermisse ich etwas?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top