I am new to Scala and I need a solution to my problem. Imagine I have these lists:
val list1 = List(1,2,3,4,5,6,7,8,9,10,11)
val list2 = List(6,5)
You can use a combination of scanLeft and splitAt:
list2.scanLeft((List.empty[Int], list1)) {
case ((_, remaining), i) => remaining.splitAt(i)
}.unzip._1.tail
Gives:
List(List(1, 2, 3, 4, 5, 6), List(7, 8, 9, 10, 11))
Brief explanation: each step of scanLeft
saves each piece of list1
and the remaining elements of list1
in a tuple. The remaining elements are split according to the size i
of next chunk, where i
is an element of list2
. In the end, all the "remainders" are thrown away by unzip._1
, and the first empty dummy-element is removed by tail
.
Note that since the list structure is immutable & persistent, the intermediate results stored in the second component of the tuple in each step do not take up any extra space, they are mere references to tails of list1
.
If what you're doing is using the second list to be the indexes on the first list:
def indexedSplit[A](myList: List[A], indx: List[Int], acc: List[List[A]]): List[List[A]] = indx match{
case Nil => acc.filter(_ != Nil).reverse
case x :: xs =>
val (h, t) = myList.splitAt(x)
indexedSplit(t, xs, h :: acc)
}
wherein you recursively walk the index list and split the list under operation at each of those points. Finally you filter out empty lists and reverse the order since you've accumulated in reverse order.
def foo[A](xs: List[A], ys: List[Int]): List[List[A]] = {
val (result, _) = ys.foldLeft((List.empty[List[A]], xs)) { case ((acc, remaining), i) =>
(remaining.take(i) :: acc, remaining.drop(i))
}
result.reverse
}
test("1") {
val list1 = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
val list2 = List(6, 5)
val result = List(List(1, 2, 3, 4, 5, 6), List(7, 8, 9, 10, 11))
foo(list1, list2) shouldBe result
}
test("2") {
val list1 = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
val list2 = List(4, 4, 3)
val result = List(List(1, 2, 3, 4), List(5, 6, 7, 8), List(9, 10, 11))
foo(list1, list2) shouldBe result
}