Grouping items in iterable order, looking for the sentinel value (in scala)

I have an iterator of lines from a very large file that needs to be put into groups as you move. I know where each group ends, because the last line of each group has a control value. So basically I want to write a function that takes an iterator and a counter value, and returns an iterator of groups, each of which ends with a sentinel value. Sort of:

scala> groups("abc.defg.hi.jklmn.".iterator, '.') res1: Iterator[Seq[Char]] = non-empty iterator scala> groups("abc.defg.hi.jklmn.".iterator, '.').toList res19: List[Seq[Char]] = List(List(a, b, c, .), List(d, e, f, g, .), List(h, i, .), List(j, k, l, m, n, .)) 

Please note that I want sentinel elements to be included at the end of each group. Here is my current solution:

 def groups[T](iter: Iterator[T], sentinel: T) = new Iterator[Seq[T]] { def hasNext = iter.hasNext def next = iter.takeWhile(_ != sentinel).toList ++ List(sentinel) } 

I think this will work, and I think that everything is in order, but the need to re-add the guard every time gives me the smell of code. Is there a better way to do this?

+5
source share
2 answers

Awful, but should be more effective than your solution:

  def groups[T](iter: Iterator[T], sentinel: T) = new Iterator[Seq[T]] { def hasNext = iter.hasNext def next = iter.takeWhile{ var last = null.asInstanceOf[T] c => { val temp = last; last = c; temp != sentinel} }.toList } 
+2
source

Less readable than yours, but more "correct" when the final group does not have a final sentinel value:

 def groups[T](iter: Iterator[T], sentinel: T) = new Iterator[Seq[T]] { def hasNext = iter.hasNext def next: Seq[T] = { val builder = scala.collection.mutable.ListBuffer[T]() while (iter.hasNext) { val x = iter.next builder.append(x) if (x == sentinel) return builder } builder } } 

Or, recursively:

  def groups[T](iter: Iterator[T], sentinel: T) = new Iterator[Seq[T]] { def hasNext = iter.hasNext def next: Seq[T] = { @scala.annotation.tailrec def build(accumulator: ListBuffer[T]): Seq[T] = { val v = iter.next accumulator.append(v) if (v == sentinel || !iter.hasNext) => accumulator else build(accumulator) } build(new ListBuffer[T]()) } } 
+5
source

Source: https://habr.com/ru/post/902150/


All Articles