1. Overview

In this tutorial, we’ll see how we can get a random element from an Array in Scala.

2. Get a Random Element From an Array

There are multiple ways to retrieve a random element from a Scala a**rray.

2.1. Using a Random Index

Since arrays are indexed, we know we can fetch an element from any valid position. We can get the size of an array very easily. With this in mind, we can generate a random number between 0 and the last index of the array, and then access that element:

scala> import scala.util.Random

scala> val arr = Array("a", "b", "c", "d", "e")
val arr: Array[String] = Array(a, b, c, d, e)

scala> arr(Random.nextInt(arr.size))
val res0: String = d

scala> arr(Random.nextInt(arr.size))
val res1: String = c

scala> arr(Random.nextInt(arr.size))
val res2: String = a

2.2. Shuffling the Array

Another possible approach is to just shuffle the array and then fetch the first element. Let’s start by seeing how we can shuffle an array:

scala> import scala.util.Random

scala> val arr = Array("a", "b", "c", "d", "e")
val arr: Array[String] = Array(a, b, c, d, e)

scala> Random.shuffle(arr)
val res0: scala.collection.mutable.ArraySeq[String] = ArraySeq(e, c, d, b, a)

scala> Random.shuffle(arr)
val res1: scala.collection.mutable.ArraySeq[String] = ArraySeq(c, e, d, b, a)

scala> Random.shuffle(arr)
val res2: scala.collection.mutable.ArraySeq[String] = ArraySeq(b, e, c, d, a)

The missing step is how to extract the first element. This can be achieved using the head() method:

scala> Random.shuffle(arr).head
val res0: String = c

scala> Random.shuffle(arr).head
val res1: String = a

scala> Random.shuffle(arr).head
val res2: String = b

This solution has a minor drawback: if the array is really big, shuffling it may cause some performance issues.

2.3. Dealing with Empty Arrays

Let’s now address the empty array edge case.

Let’s start by looking at the first solution we described, which generated a random index:

scala> val arr = Array[String]()
val arr: Array[String] = Array()

scala> arr(Random.nextInt(arr.size))
java.lang.IllegalArgumentException: bound must be positive
  ...
  at dotty.tools.repl.Main.main(Main.scala)

We get an exception. This happens because the random number generator we use requires a positive upper bound. In the case of the empty array, we are passing 0, which is its size. The best solution, in this case, would be to simply check if the array is empty:

scala> arr.isEmpty
val res0: Boolean = true

We can then add some additional logic to simply return an appropriate value or error.

Let’s see what would happen in our second solution that shuffles the array:

scala> import scala.util.Random

scala> val arr = Array[String]()
val arr: Array[String] = Array()

scala> Random.shuffle(arr)
val res8: scala.collection.mutable.ArraySeq[String] = ArraySeq()

The shuffling method works even for empty arrays. However, if we try to extract the first element we’ll get an exception:

scala> Random.shuffle(arr).head
java.lang.ArrayIndexOutOfBoundsException: 0
  ...
  at dotty.tools.repl.Main.main(Main.scala)

The solution is to replace the head() method with the headOption() method:

scala> import scala.util.Random

scala> val arr = Array[String]()
val arr: Array[String] = Array()

scala> Random.shuffle(arr).headOption
val res0: Option[String] = None

scala> val arr = Array("a","b","c","d","e")
val arr: Array[String] = Array(a, b, c, d, e)

scala> Random.shuffle(arr).headOption
val res1: Option[String] = Some(b)

Now we just need to use the result as needed in our application.

3. Conclusion

In this article, we saw how to get a random element from a Scala array. We can either shuffle the array or generate a random index. Both approaches have different implications.  In the first case, we need to be aware of performance implications when we have very large arrays.  In the latter case, we need to add an explicit check for empty arrays.


» 下一篇: Tapir 介绍