oshai
oshai

Reputation: 15355

create n iterators from one iterator

I wanted to create n iterators from one in scala using 'duplicate'

came up with that code:

def getNIterators[T](it: Iterator[T], n: Int) : Seq[Iterator[T]] = {
  getNMoreIterators(Seq(it), n-1)
}

private def getNMoreIterators[T](seq: Seq[Iterator[T]], n: Int) : Seq[Iterator[T]] = {
if (n <= 0) return seq else {
  val (it1, it2) = seq.head.duplicate
  Seq(it1, it2) ++ getNMoreIterators(seq.tail, n-1)
}
}

Can I improve it to tailrecurtion or a method that is more efficient?

Upvotes: 0

Views: 270

Answers (2)

Łukasz
Łukasz

Reputation: 8663

You are actually destroying the current Iterator and getting 2 new in return. I think it would me more efficient to just destroy Iterator once and put it in a Seq, getting iterators from there (that's just an intuition, I didn't bemchmark it).

def getNIterators[A](it: Iterator[A], n: Int) : Seq[Iterator[A]] = {
  val seq = it.toSeq
  Seq.fill(n)(seq.iterator)
}

You might want to read about problems with duplicate here: How to copy iterator in Scala? and here: How to clone an iterator?

Edit:

Ok then, if you don't want to consume whole iterator in the beginning, consider using a Stream

def getNIterators[A](it: Iterator[A], n: Int) : Seq[Iterator[A]] = {
  val seq = it.toStream
  Seq.fill(n)(seq.iterator)
}

It will consume Iterator as needed (except for the head, it will be consumed immidietly), and all the Iterators are independent.

scala> (1 to 4).iterator.map(s => {println(s); s})
res12: Iterator[Int] = non-empty iterator

scala> getNIterators(res12, 4)
1
res13: Seq[Iterator[Int]] = List(non-empty iterator, non-empty iterator, non-empty iterator, non-empty iterator)

scala> res13.map(_.next)
res14: Seq[Int] = List(1, 1, 1, 1)

scala> res13.map(_.next)
2
res15: Seq[Int] = List(2, 2, 2, 2)

scala> res13.map(_.next)
3
res16: Seq[Int] = List(3, 3, 3, 3)

scala> res13.map(_.next)
4
res17: Seq[Int] = List(4, 4, 4, 4)

Upvotes: 1

Tzach Zohar
Tzach Zohar

Reputation: 37822

How about:

def getNIterators[T](it: Iterator[T], n: Int) : Seq[Iterator[T]] = {
   (1 to n).map(_ => it.duplicate._2)
}

Upvotes: 0

Related Questions