This will only work with ranges with a step (by
) of 1 so far, but is a simple solution to splitting a range into a given number of sub-ranges:
def splitRange(r: Range, chunks: Int): Seq[Range] = {
if (r.step != 1)
throw new IllegalArgumentException("Range must have step size equal to 1")
val nchunks = scala.math.max(chunks, 1)
val chunkSize = scala.math.max(r.length / nchunks, 1)
val starts = r.by(chunkSize).take(nchunks)
val ends = starts.map(_ - 1).drop(1) :+ r.end
starts.zip(ends).map(x => x._1 to x._2)
}
This is what you get on the Scala REPL:
scala> splitRange(0 to 10, 2)
res5: Seq[Range] = Vector(Range(0, 1, 2, 3, 4), Range(5, 6, 7, 8, 9, 10))
scala> splitRange(0 to 10, 11)
res0: Seq[Range] = Vector(Range(0), Range(1), Range(2), Range(3), Range(4), Range(5), Range(6), Range(7), Range(8), Range(9), Range(10))
It also handles boundary conditions such as more chunks than elements or empty ranges rather well:
scala> splitRange(0 to 10, 12)
res1: Seq[Range] = Vector(Range(0), Range(1), Range(2), Range(3), Range(4), Range(5), Range(6), Range(7), Range(8), Range(9), Range(10))
scala> splitRange(0 until 0, 2)
res4: Seq[Range] = Vector()
scala> splitRange(0 to 10, -1)
res1: Seq[Range] = Vector(Range(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10))