Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to group a variable-length, repeating sequence in Scala

I have a collection of ints that repeat themselves in a pattern:

val repeatingSequence = List(1,2,3,1,2,3,4,1,2,1,2,3,4,5)

I'd like to section that List up when the pattern repeats itself; in this case, when the sequence goes back to 1:

val groupedBySequence = List(List(1,2,3), List(1,2,3,4), List(1,2), List(1,2,3,4,5))

Notice that I'm grouping when the sequence jumps back to 1, but that the sequence can be of arbitrary length. My colleague and I have solved it by adding an additional method called 'groupWhen'

class IteratorW[A](itr: Iterator[A]) {
  def groupWhen(fn: A => Boolean): Iterator[Seq[A]] = {
    val bitr = itr.buffered
    new Iterator[Seq[A]] {
      override def hasNext = bitr.hasNext
      override def next = {
        val xs = collection.mutable.ListBuffer(bitr.next)
        while (bitr.hasNext && !fn(bitr.head)) xs += bitr.next
        xs.toSeq
      }
    }
  }
}
implicit def ToIteratorW[A](itr: Iterator[A]): IteratorW[A] = new IteratorW(itr)

> repeatingSequence.iterator.groupWhen(_ == 1).toSeq
List(List(1,2,3), List(1,2,3,4), List(1,2), List(1,2,3,4,5))

However, we both feel like there's a more elegant solution lurking in the collection library.

like image 696
Matt Hughes Avatar asked Jul 23 '11 13:07

Matt Hughes


2 Answers

Given an iterator itr, this will do the trick:

val head = iter.next()
val out = (
  Iterator continually {iter takeWhile (_ != head)}
  takeWhile {!_.isEmpty}
  map {head :: _.toList}
).toList
like image 60
Kevin Wright Avatar answered Sep 21 '22 13:09

Kevin Wright


As well all know, fold can do everything... ;)

  val rs = List(1,2,3,1,2,3,4,1,2,1,2,3,4,5)
  val res = (rs++List(1)).foldLeft((List[List[Int]](),List[Int]()))((acc,e) => acc match {
    case (res,subl) => {
      if (e == 1) ((subl.reverse)::res,1::Nil) else (res, e::subl)
    }
  })
  println(res._1.reverse.tail)

Please regard this as an entry for the obfuscated Scala contest rather than as a real answer.

like image 35
Kim Stebel Avatar answered Sep 24 '22 13:09

Kim Stebel