Y Mika
Y Mika

Reputation: 81

Splitting List into List of List

How can I convert:

List(1,1,1,1,4,2,2,2,2)

into:

List(List(1,1,1,1), List(2,2,2,2))

Thought this would be the easiest way to show what I'm looking for. I am having a hard time trying to find the most functional way to do this with a large list that needs to be separated at a specific element. This element does not show up in the new list of lists. Any help would be appreciated!

Upvotes: 2

Views: 494

Answers (5)

lprakashv
lprakashv

Reputation: 1159

def convert(list: List[Int], separator: Int): List[List[Int]] = {
  @scala.annotation.tailrec
  def rec(acc: List[List[Int]], listTemp: List[Int]): List[List[Int]] = {
    if (listTemp.isEmpty) acc 
    else {
      val (l, _ :: r) = listTemp.span(_ != separator)
      rec(acc ++ List(l), r)
    }
  }

  rec(List(), list)
}

Upvotes: 0

Xavier Guihot
Xavier Guihot

Reputation: 61666

Given a list and a delimiter, in order to split the list in 2:

val list = List(1, 1, 1, 1, 4, 2, 2, 2, 2)
val delimiter = 4
  • you could use a combination of List.indexOf, List.take and List.drop:

    val splitIdx = list.indexOf(delimiter)
    List(list.take(splitIdx), list.drop(splitIdx + 1))
    
  • you could use List.span which splits the list into a tuple given a predicate:

    list.span(_ != delimiter) match { case (l1, l2) => List(l1, l2.tail) }
    

in order to produce:

List(List(1, 1, 1, 1), List(2, 2, 2, 2))

Upvotes: 2

Tim
Tim

Reputation: 27356

This is the cleanest way to do this

val (l, _ :: r) = list.span( _ != 4)

The span function splits the list at the first value not matching the condition, and the de-structuring on the left-hand side removes the matching value from the second list.

This will fail if there is no matching value.

Upvotes: 2

ziggystar
ziggystar

Reputation: 28680

scala> val l = List(1,1,1,1,4,2,2,2,2)
l: List[Int] = List(1, 1, 1, 1, 4, 2, 2, 2, 2)

scala> l.splitAt(l.indexOf(4))
res0: (List[Int], List[Int]) = (List(1, 1, 1, 1),List(4, 2, 2, 2, 2))

Upvotes: 1

Tzach Zohar
Tzach Zohar

Reputation: 37832

If you want to support multiple instances of that separator, you can use foldRight with some list "gymnastics":

// more complex example: separator (4) appears multiple times
val l = List(1,1,1,1,4,2,2,2,2,4,5,6,4)

val separator = 4

val result = l.foldRight(List[List[Int]]()) {
  case (`separator`, res) => List(Nil) ++ res
  case (v, head :: tail) => List(v :: head) ++ tail
  case (v, Nil) => List(List(v))
}

// result: List(List(1, 1, 1, 1), List(2, 2, 2, 2), List(5, 6))

Upvotes: 4

Related Questions