Selected Reading

Scala - Ranges



In Scala, Range is an ordered sequence of integers. Range can have start and endpoints. Range is part of the collection. You can use range of built-in functions in Scala. Range is an organized series of integers.

Creating Range

You can create range for negative, positive and decimal values. Ranges are ordered datatype in Scala. You can use filter, map and foreach functions to use range. You can create ranges in various ways as explained below.

1. Using Companion Object

You can provide start and endpoint for a range. You can use the Range.inclusive method to do this. For example,

// Creating object
object MainObject
{
   // Main method
   def main(args: Array[String])
   {
      val rangeInclByTwo = Range.inclusive(1, 10, 2)
      println(rangeInclByTwo.toList) // should be List(1, 3, 5, 7, 9)
   }
}

The output will be List(1, 3, 5, 7, 9). It is starting from 1 and ends in 10 with step size is 2.

Another code will be,

// Creating object
object MainObject
{
   // Main method
   def main(args: Array[String])
   {
      val rangeExclStepTwo = Range(1, 10, 2)
      println(rangeExclStepTwo.toList) // should be List(1, 3, 5, 7, 9)
   }
}

Note that there is a difference between these codes. First code has rangeInclByTwo and second code has rangeExclStepTwo. It means the first one has an inclusive range and the second one has an exclusive range.

2. Using to and until methods

You can use until and methods to define ranges. For example,

// Creating object
object MainObject
{
   // Main method
   def main(args: Array[String])
   {
      val rangeToStepThree = 1 to 10 by 3
      println(rangeToStepThree.toList) // should be List(1, 4, 7, 10)
   }
}

The output will be List(1, 4, 7, 10)

This code is the same as Range.inclusive(1, 10, 3). You can also give range by using until. For example,

// Creating object
object MainObject
{
   // Main method
   def main(args: Array[String])
   {
      val rangeUntilStepTwo = 1 until 10 by 2
      println(rangeUntilStepTwo.toList) // should be List(1, 3, 5, 7, 9)
   }
}

The output will be List(1, 3, 5, 7, 9)

3. Range with Step

The default step is 1 while creating ranges in Scala. It means the difference of two consecutive values will be 1. You can also set step size while defining ranges in Scala. You can use by keyword to set step size in range. For example,

// Creating object
object MainObject
{
   // Main method
   def main(args: Array[String])
   {
      val evenRange = 2 to 100 by 2
      println(evenRange.head) // should be 2
      println(evenRange.last) // should be 100
   }
}

The output will be,

2
100

You can also use companion objects to set step size while creating ranges. For example,

// Creating object
object MainObject
{
   // Main method
   def main(args: Array[String])
   {
      val rangeStepByThree = Range(1, 10, 3)
      println(rangeStepByThree.toList) // should be List(1, 4, 7)
   }
}

The output will be List(1, 4, 7)

You can set step size as a negative value too. For example,

// Creating object
object MainObject
{
   // Main method
   def main(args: Array[String])
   {
      val reverseRangeFrom10 = 10 to 1 by -2
      println(reverseRangeFrom10.head) // should be 10
      println(reverseRangeFrom10.last) // should be 2
   }
}

The output will be,

10
2

The variable will contain even numbers from 10 to 2 in descending order.

Note that if you set the positive step size in reverseRangeFrom10 then it will be empty. It is not possible to start from 10 with step size 2 and end with 2. It will never reach the end point.

You can also create a range of negative numbers. For example,

// Creating object
object MainObject
{
   // Main method
   def main(args: Array[String])
   {
      val negativeRangeByThree = -1 to -10 by -3
      println(negativeRangeByThree.toList) // should be List(-1, -4, -7, -10)
   }
}

The output will be List(-1, -4, -7, -10)

Note that if you set positive step size. Then it will never reach the end point because you can reach to -10 from starting from -1 while adding positive step size every time.

4. Non-Integer Range

We discussed ranges with Integers. Now, we will explain ranges with decimal numbers in this section. You need to set step size explicitly for decimal numbers. There is no default step size in case of decimal numbers.

For example,

// Creating object
object MainObject
{
   // Main method
   def main(args: Array[String])
   {
      val tripleRange = 1.5 to 2.5 by 0.3
      println(tripleRange.toList)
   }
}

The output will be List(1.5, 1.8, 2.1, 2.4). But starting from Scala 2.12.6, it is not recommended to create range in this way. It is because of problems with approximating decimal points. You can use BiDecimal instead of Double to create such ranges in Scala.

For example,

// Creating object
object MainObject
{
   // Main method
   def main(args: Array[String])
   {
      val customDecimalRange = BigDecimal(0.5) to BigDecimal(1.5) by 0.25
      println(customDecimalRange) // should be List(0.5, 0.75, 1.0, 1.25, 1.5)
   }
}

The output will be List(0.5, 0.75, 1.0, 1.25, 1.5)

Useful Methods on Range

The methods that work with collections can also be used with ranges. We will discuss some of them here.

(a) Iterate and Filter

There are various iterates available like filter, filternot, map and foreach. You can use these in ranges. These methods are inherited from trait TraversableLike. You can use the toList function to convert a range into a list.

// Creating object
object MainObject
{
   // Main method
   def main(args: Array[String])
   {
      val customRange = 5 to 15

      val multiplesOfThree = customRange.filter(_ % 3 == 0)
      println(multiplesOfThree) // should be List(6, 9, 12, 15)

      val squaredValues = customRange.map(n => n * n)
      println(squaredValues) // should be List(25, 36, 49, 64, 81, 100, 121, 144, 169, 196)
   }
}

(b) Take and Drop

Range has methods like, take, takeWhile, drop, dropWhile etc. These methods return another range.

// Creating object
object MainObject
{
   // Main method
   def main(args: Array[String])
   {
       val customRange = 5 to 15

       val takeThree: Range = customRange.take(3)
       println(takeThree.head) // should be 5
       println(takeThree.last) // should be 7

       val dropTwo: Range = customRange.drop(2)
       println(dropTwo.head) // should be 7
       println(dropTwo.last) // should be 5
   }
}

Conclusion

Ranges are generally used in the loops and iteration. Range has three constraints, i.e, start, end, and step size. Ranges are immutable and part of collections in Scala. You can create various sequences and series of integers and decimal numbers. Range provides faster execution.

Advertisements