What is the general accepted implementation of a recursive split-by-token function?
For example:
val s: List[Char] = 'F' :: 'o' :: 'o' :: ' ' :: 'b' :: 'a' :: 'r' :: ' ' :: 'f' :: 'o':: 'o':: ' ' :: 'b' :: 'a' :: 'r' :: Nil
fooSplit(s) // -> List(List('F','o','o'), List('b', 'a', 'r'), List('f', 'o', 'o'), List('b','a','r'))
Here are the base cases I've come up with, when doing pattern matching on the parameter:
def fooSplit(text: List[Char]): List[List[Char]] = text match {
case x :: ' ' :: xs =>
// Somehow append old list to fooSplit(xs) <?>
println(x "_")
fooSplit(xs)
case x :: xs =>
println(x "")
fooSplit(xs)
case Nil => Nil
}
Most of my attempts following the above structure almost always lead to List('F', List('O', List('O'), ...)...)
. Without coming up with some very sinister double pattern matching I can't seem to wrap my head on to extend instead of append to the inside list.
I would also like to quote the Scala Cookbook:
Use flatMap in situations where you run map followed by flatten. The specific situation is this:
• You’re using map (or a for/yield expression) to create a new collection from an existing collection.
• The resulting collection is a list of lists.
• You call flatten immediately after map (or a for/yield expression)
This seems like a very possible case to use flatMap, could anyone provide insight on this?
CodePudding user response:
Just because you're returning an instance of List[List[String]]
doesn't mean you need to flatten it, sometimes you might need those values. I would suggest this:
scala> import scala.annotation.tailrec
import scala.annotation.tailrec
scala> def fooSplit(text: List[Char]): List[List[Char]] = {
|
| @tailrec
| def fooSplitHelper(currentListBeforeToken: List[Char] = List.empty, list: List[Char], acc: List[List[Char]] = List.empty): List[List[Char]] = {
| if (list.isEmpty) {
| acc : currentListBeforeToken
| } else {
| list.head match {
| case ' ' => fooSplitHelper(List.empty[Char], list.tail, acc : currentListBeforeToken)
| case otherChar => fooSplitHelper(currentListBeforeToken : otherChar, list.tail, acc)
| }
| }
| }
|
| fooSplitHelper(list = text)
| }
def fooSplit(text: List[Char]): List[List[Char]]
scala> fooSplit(s)
val res0: List[List[Char]] = List(List(F, o, o), List(b, a, r), List(f, o, o), List(b, a, r))