Подтвердить что ты не робот

Потреблять предметы из scala Iterator

Я запутался в поведении метода take в признаке Iterator. Похоже, что он не потребляет предметы. Вот пример:

scala> Iterator(1,2,3)
res0: Iterator[Int] = non-empty iterator

scala> res0 take 2 toArray
res1: Array[Int] = Array(1, 2)

scala> res0.next
res2: Int = 1

По-видимому, шаг 2 потребляет два элемента, но на шаге 3 Iterator все еще находится на первом месте. Глядя на реализацию, я не вижу никаких копий или буферизации, просто новый Iterator, который делегирует основную. Как это возможно? Как я могу реально потреблять n элементов?

4b9b3361

Ответ 1

Итератор, о котором идет речь, определен в IndexedSeqLike#Elements (source). Недавно был отправлен билет о несогласованном поведении take в разных реализациях итератора.

Чтобы действительно потреблять N элементов, вызовите Iterator#next N раз.

Возможно, вы захотите использовать Stream, который является ленивым (например, Iterator), но также является неизменным (в отличие от Iterator).

scala> val s = Stream(1, 2, 3)
s: scala.collection.immutable.Stream[Int] = Stream(1, ?)

scala> s.take(2).toList
res43: List[Int] = List(1, 2)

scala> s.take(2).toList
res44: List[Int] = List(1, 2)

scala> s.drop(2).toList
res45: List[Int] = List(3)

scala> {val (s1, s2) = s.splitAt(2); (s1.toList, s2.toList)}
res46: (List[Int], List[Int]) = (List(1, 2),List(3))

Ответ 2

Спасибо, ребята.

Это мое решение, чтобы потреблять пучки элементов из Iterator:

  implicit def consumable(i: Iterator[_]) = new {
    def next(n: Int) = {
      (for (_ <- 1 to n) yield i.next()).iterator
    }
    def skip(n: Int) {
      (1 to n).foreach(_ => i.next())
    }
  }

любые комментарии будут приветствоваться.

Ответ 3

Вы хотите потреблять предметы, drop их. Обратите внимание, что большинство методов, называемых Iterator, сделает Iterator бесполезным для дальнейшего использования - бесполезным в том смысле, что поведение undefined и может быть изменено.