Question

Je cherche à étendre l'itérateur pour créer une nouvelle méthode takeWhileInclusive, qui fonctionnera comme takeWhile mais comprennent le dernier élément.

Ma question est ce qui est préférable d'étendre le iterator de retourner une nouvelle iterator que je voudrais être paresseux évalué. Issu d'un milieu C # I utilisation normale IEnumerable et utiliser le mot-clé yield, mais une telle option ne semble pas exister dans Scala.

par exemple, je pourrais avoir

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

dans ce cas, le takeWhileInclusive ne devrait résoudre le prédicat sur les valeurs jusqu'à ce que je reçois le résultat supérieur à 6, et il comprendra ce premier résultat

jusqu'à présent, j'ai:

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

class IteratorExtension[T <: Any](i : Iterator[T]) {
  def takeWhileInclusive(predicate:(T) => Boolean) = ?
}
Était-ce utile?

La solution

Ceci est un cas où je trouve la solution supérieure mutable:

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)

Autres conseils

Vous pouvez utiliser la méthode span de Iterator faire cette jolie proprement:

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

(0 until 10).toIterator.takeWhileInclusive(_ < 4).toList donne List(0, 1, 2, 3, 4), par exemple.

Ce qui suit nécessite scalaz pour obtenir fold sur un tuple (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]}

Ici, il est au travail:

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)

Vous pouvez rouler votre propre fois sur une paire comme ceci:

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

Et il y a une erreur dans votre implicite. Ici, il est fixé:

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)

Après votre mise à jour:

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)

timeConsumeDummy est appelé 4 fois. Est-ce que je manque quelque chose?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top