Skip to content

Instantly share code, notes, and snippets.

@DmitryBe
Forked from asieira/splitRange.md
Created April 5, 2017 00:41
Show Gist options
  • Save DmitryBe/d9df65bc8c691e01816d02798b22cff4 to your computer and use it in GitHub Desktop.
Save DmitryBe/d9df65bc8c691e01816d02798b22cff4 to your computer and use it in GitHub Desktop.
Scala - split Range (x to y, x until y) into similarly-sized sub-Ranges

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))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment