Home > database >  Splitting a list of strings into several lists at every predicate scala
Splitting a list of strings into several lists at every predicate scala

Time:12-05

Is there a way for splitting a list of strings like following:

List("lorem", "ipsum" ,"X", "sit", "amet", "consectetur")

At every predicate like x => x.equals("X") into several lists that the result would be:

List(List("lorem", "ipsum"), List("sit", "amet", "consectetur"))

That all in a simple functional way?

CodePudding user response:

You can use a tail-recursive function to easily keep track of each chunk like this:

def splitEvery[A](data: List[A])(p: A => Boolean): List[List[A]] = {
  @annotation.tailrec
  def loop(remaining: List[A], currentChunk: List[A], acc: List[List[A]]): List[List[A]] =
    remaining match {
      case a :: tail =>
        if (p(a))
          loop(
            remaining = tail,
            currentChunk = List.empty,
            currentChunk.reverse :: acc
          )
        else
          loop(
            remaining = tail,
            a :: currentChunk,
            acc
          )
      
      case Nil =>
        (currentChunk.reverse :: acc).reverse
    }
  
  loop(
    remaining = data,
    currentChunk = List.empty,
    acc = List.empty
  )
}

Which can be used like this:

val data = List("lorem", "ipsum" ,"X", "sit", "amet", "consectetur")
val result = splitEvery(data)(_ == "X")
// result: List[List[String]] = List(List(lorem, ipsum), List(sit, amet, consectetur)
)

You can see the code running here.

CodePudding user response:

The unfold() (Scala 2.13.x) way.

val lst =
  List("X","lorem","ipsum","X","sit","amet","X","consectetur","X")

List.unfold(lst){st =>
  Option.when(st.nonEmpty){
    val (nxt, rst) = st.span(_ != "X")
    (nxt, rst.drop(1))
  }
}
//res0: List[List[String]] = List(List()
//                              , List(lorem, ipsum)
//                              , List(sit, amet)
//                              , List(consectetur))
  • Related