Starting Scala 2.13
, List
is now provided with the unfold
builder which can be combined with String::span
:
List.unfold("aaaabbaaacdeeffg") {
case "" => None
case rest => Some(rest.span(_ == rest.head))
}
// List[String] = List("aaaa", "bb", "aaa", "c", "d", "ee", "ff", "g")
or alternatively, coupled with Scala 2.13
's Option#unless
builder:
List.unfold("aaaabbaaacdeeffg") {
rest => Option.unless(rest.isEmpty)(rest.span(_ == rest.head))
}
// List[String] = List("aaaa", "bb", "aaa", "c", "d", "ee", "ff", "g")
Details:
- Unfold (
def unfold[A, S](init: S)(f: (S) => Option[(A, S)]): List[A]
) is based on an internal state (init
) which is initialized in our case with "aaaabbaaacdeeffg"
.
- For each iteration, we
span
(def span(p: (Char) => Boolean): (String, String)
) this internal state in order to find the prefix containing the same symbol and produce a (String, String)
tuple which contains the prefix and the rest of the string. span
is very fortunate in this context as it produces exactly what unfold
expects: a tuple containing the next element of the list and the new internal state.
- The unfolding stops when the internal state is
""
in which case we produce None
as expected by unfold to exit.