Reputation: 692
I would like to perform something like unFlatMap. Lets say that I have stream:
Stream("|","A","d","a","m","|","J","o","h","n", ...)
Stream could be infinite. I would like to convert it to:
Stream("Adam", "John", ...)
Ofcourse it is only example. In general I would like to perform some operation on elements separated by delimiter, Generic signature would be:
def unFlatMap[B](isSeparator:A => Boolean)(group:Seq[A] => B):TraversableOnce[B]
How to do that in clean and memory efficient way?
Upvotes: 3
Views: 169
Reputation: 3699
You could do something like this:
def groupStream[A, B](s: Stream[A])(isSeparator: A => Boolean)(group: Seq[A] => B): Stream[B] =
group(s.takeWhile(!isSeparator(_)).toList) #:: groupStream(s.dropWhile(!isSeparator(_)).drop(1))(isSeparator)(group)
Or if you want an easier to read but more verbose version:
def groupStream[A, B](s: Stream[A])(isSeparator: A => Boolean)(group: Seq[A] => B): Stream[B] = {
def isNotSeparator(i: A): Boolean = ! isSeparator(i)
def doGroupStream(s: Stream[A]): Stream[B] =
group(s.takeWhile(isNotSeparator).toList) #:: doGroupStream(s.dropWhile(isNotSeparator).drop(1))
doGroupStream(s)
}
If you want a implicit method on Stream, you could also do
implicit class ImprovedStream[A](val s: Stream[A]) extends AnyVal {
def groupStream[B](isSeparator: A => Boolean)(group: Seq[A] => B): Stream[B] = {
def isNotSeparator(i: A): Boolean = ! isSeparator(i)
def doGroupStream(st: Stream[A]): Stream[B] =
group(st.takeWhile(isNotSeparator).toList) #:: doGroupStream(st.dropWhile(isNotSeparator).drop(1))
doGroupStream(s)
}
}
Now, using your example:
val a = Stream("|" ,"A","d","a","m","|","J","o","h","n", "|", "M", "a", "r", "y", "|", "J", "o", "e")
val c = groupStream(a)(_ == "|")(_.mkString)
c.take(10).toList
// List[String] = List("", Adam, John, Mary, Joe, "", "", "", "", "")
Using the implicit version:
val c = groupStream(a)(_ == "|")(_.mkString)
Upvotes: 4