score:21

convert into `Vector` and get random element from it

``````scala> val fruits = Set("apple", "grape", "pear", "banana")
fruits: scala.collection.immutable.Set[String] = Set(apple, grape, pear, banana)

scala> import scala.util.Random
import scala.util.Random

scala> val rnd=new Random
rnd: scala.util.Random = scala.util.Random@31a9253

scala> fruits.toVector(rnd.nextInt(fruits.size))
res8: String = apple
``````

score:0

Not converting the `Set` to an ordered collection but using `zipWithIndex` we can attribute an index to each item in the collection,

``````fruits.zipWithIndex
Set((apple,0), (grape,1), (pear,2), (banana,3))
``````

Thus for `val rnd = util.Random.nextInt(fruits.size)`,

``````fruits.zipWithIndex.find( _._2 == rnd)
Option[(String, Int)] = Some((banana,3))
``````

Given an empty set,

``````Set[String]().zipWithIndex.find( _._2 == 3)
Option[(String, Int)] = None
``````

score:0

If you don't mind an `O(n)` solution:

``````import util.Random

// val fruits = Set("apple", "grape", "pear", "banana")
// "pear"
``````

score:1

``````   import Scala.util.Random

val fruits = Set("apple", "grape", "pear", "banana").toVector

val sz =fruits.size

val num = Random.nextInt(sz)

fruits(num)
``````

score:2

Solution1

Random way ( `import scala.util.Random` )

``````scala>  fruits.toList(Random.nextInt(fruits.size))
res0: java.lang.String = banana
``````

Solution2

Math way (no imports)

``````scala> fruits.toList((math.random*fruits.size).toInt)
res1: String = banana
``````

score:2

You can directly access an element of a Set with slice. I used this when I was working with a set that was changing in size, so converting it to a Vector every time seemed like overkill.

``````val roll = new Random ()

val n = roll nextInt (fruits size)
fruits slice (n, n + 1) last
``````

score:3

Drawing inspiration from the other answers to this question, I've come up with:

``````private def randomItem[T](items: Traversable[T]): Option[T] = {
val i = Random.nextInt(items.size)
}
``````

This doesn't copy anything, doesn't fail if the `Set` (or other type of `Traversable`) is empty, and it's clear at a glance what it does. If you're certain that the `Set` is not empty, you could use `.head` instead of `headOption`, returning a `T`.

score:22

So, every answer posted before has complexity O(n) in terms of space, since they create a copy a whole collection in some way. Here is a solution without any additional copying (therefore it is "constant space"):

``````def random[T](s: Set[T]): T = {
val n = util.Random.nextInt(s.size)
s.iterator.drop(n).next
}
``````