Scala FAQ: Using Scala, how do I generate random numbers without duplicate values, i.e., how do I generate a sequence of random, unique values?
Solution
To show the solution, here’s a Scala 3 function that generates a random sequence of unique integer values:
import scala.util.Random
def generateUniqueRandomNumbers(
    count: Int, 
    minInclusive: Int, 
    maxExclusive: Int
): Vector[Int] =
    require(maxExclusive - minInclusive + 1 >= count, "Range is too small to generate the desired number of unique random numbers")
    val random = Random()
    var numbers = Set.empty[Int]
    while
        numbers.size < count
    do
        numbers += random.nextInt((maxExclusive - minInclusive) + 1) + minInclusive
    numbers.toVector
// call the function and use it like this
val uniqueRandomNumbers = generateUniqueRandomNumbers(20, 1, 25)
println(uniqueRandomNumbers)
Keys to the solution
As shown in the code, the keys to this solution are:
- Generate the random values using the Scala 
Randomtype. - Initially put the numbers in a 
Set; this is because aSetis a type that only contains unique values, which is what we want. - At the end of the function I convert the 
Setto aVector, but this is optional. You can just return theSet[Int], if you prefer. 
Also:
- The 
requirepart of this solution is extremely important. If you don’t include it --- or something similar to it, like your own customException--- you can create an infinite loop. 
For example, this use works fine because the count is 5, and the minInclusive and maxExclusive values allow for the creation of five values:
generateUniqueRandomNumbers(5, 1, 5)   // result: Vector(5, 1, 2, 3, 4)
But if the count is larger than the range you’re trying to create, you’ll create an infinite loop without the require statement, as shown in the Scala REPL:
scala> generateUniqueRandomNumbers(10, 1, 5)
java.lang.IllegalArgumentException: requirement failed:
     Range is too small to generate the desired number of unique random numbers
     at scala.Predef$.require(Predef.scala:337)
Handling require’s exception
In idiomatic Scala code — i.e., using Scala best practices — our functions don’t throw exceptions, so wrapping this function in the Try constructor is one way to handle this situation:
import scala.util.{Random, Try}
def generateUniqueRandomNumbers(
    count: Int, 
    minInclusive: Int, 
    maxExclusive: Int
): Try[Vector[Int]] = Try {   //<-- i added Try here
    require(maxExclusive - minInclusive + 1 >= count, "Range is too small to generate the desired number of unique random numbers")
    val random = Random()
    var numbers = Set.empty[Int]
    while
        numbers.size < count
    do
        numbers += random.nextInt((maxExclusive - minInclusive) + 1) + minInclusive
    numbers.toVector
}
The Scala REPL shows how this works:
scala> generateUniqueRandomNumbers(5, 1, 10)
val res0: util.Try[Vector[Int]] = Success(Vector(1, 6, 2, 7, 3))
As you can see in the res0 value, this is the result of that function call:
Success(Vector(1, 6, 2, 7, 3))
Because we now have a Vector wrapped inside a Success value, you’ll want to handle that Success value with something like a match expression:
res0 match
    case Success(seq) => println(seq)
    case Failure(err) => System.err.println(err)
| this post is sponsored by my books: | |||
         
           #1 New Release  | 
      
         
           FP Best Seller  | 
      
         Learn Scala 3  | 
      
         Learn FP Fast  | 
  
Related information
If you don’t know anything about handling values like Try, Option, or Either with match expressions, see these links: