Вы можете использовать foldLeft
, затем map
, если порядок не имеет значения, вы можете избавиться от reverse
s:
case class cs(name: String, size: Int)
val cl: List[cs] = List(cs("abc1", 3), cs("abc2", 2), cs("abc3", 1), cs("abc4", 2), cs("abc5", 2), cs("abc6", 1), cs("abc7", 5))
def splitBy(l: List[cs], chunkSize: Int = 5): List[List[cs]] =
l.foldLeft(List[(List[cs],Int)]()) {
case (accum @ (_, size: Int) :: _, next: cs) if size + next.size > chunkSize =>
(next :: Nil, next.size) :: accum
case ((chunk, size: Int) :: rest, next: cs) =>
(next :: chunk, size + next.size) :: rest
case (Nil, next: cs) =>
(next :: Nil, next.size) :: Nil
}.map {
case (chunk, size: Int) =>
chunk.reverse
}.reverse
splitBy(cl, 5) foreach println
Вывод:
List(cs(abc1,3), cs(abc2,2))
List(cs(abc3,1), cs(abc4,2), cs(abc5,2))
List(cs(abc6,1))
List(cs(abc7,5))
Я изначально неверно истолковал вопрос, чтобы обозначить, что вы хотите, чтобы куски составляли по крайней мере chunkSize
.Это был мой старый ответ, который я оставлю здесь для потомков, используя scanLeft
, за которым следует collect
:
case class cs(name: String, size: Int)
val cl: List[cs] = List(cs("abc1", 3), cs("abc2", 2), cs("abc3", 1), cs("abc4", 2), cs("abc5", 2), cs("abc6", 1), cs("abc7", 5))
def splitBy(l: List[cs], chunkSize: Int = 5): List[List[cs]] =
l.scanLeft(List[cs]() -> 0) {
case ((_, size: Int), next: cs) if size >= chunkSize =>
(next :: Nil, next.size)
case ((chunk, size: Int), next: cs) =>
(next :: chunk, size + next.size)
}.collect {
case (chunk, size: Int) if size >= chunkSize =>
chunk.reverse
}
splitBy(cl, 5) foreach println
Вывод:
List(cs(abc1,3), cs(abc2,2))
List(cs(abc3,1), cs(abc4,2), cs(abc5,2))
List(cs(abc6,1), cs(abc7,5))