In Elixir, to choose a random element from an enumerable data structure (e.g. list, range), we use Enum.random/1
. This function will pick a single element, with every element having equal probability of being picked. Picking a single random value from a range is executed in constant time, without traversing the whole range.
Enum.random(1..10)
# => 7
<<Enum.random(?A..?Z)>>
# => "K"
[Enum.random(?A..?Z)]
# => ~c"J"
To choose more than one element from an enumerable data structure, use Enum.take_random/2
. To sort an enumerable data structure in a random order, use Enum.shuffle/1
.
Elixir does not have its own functions for picking a random float. To do that, we have to use Erlang's rand
module, which also happens to be what Enum.random
uses under the hood.
Choosing a random float (equal to or greater than 0.0 and less than 1.0):
:rand.uniform()
# => 0.275329955448815
Choosing a random float (equal to or greater than a
and less than b
):
a = 13
b = 20
:rand.uniform() * (b - a) + a
# => 18.96815556890448
All the functions mentioned above choose a random value with every possible value having the same probability of being chosen. That's called a uniform distribution. The rand
module also offers normal/0
and normal/2
functions that choose a random float with a normal distribution.
It's important to understand that the "random" values are generated by a pseudo random number generator. A PRNG is an algorithm that, given an initial value called a seed, will generate a sequence of numbers that seems random, but isn't random at all.
This fact might be useful for debugging. You can force Erlang's (and thus Elixir's) pseudo random number generator to produce the same sequence values by resetting its seed using :rand.seed/2
. The first argument is a specific PRNG algorithm, and the second a three-integer-tuple - the seed.
:rand.seed(:exsss, {1, 2, 3})
Enum.take_random(100..999, 3)
# => [680, 127, 622]
:rand.seed(:exsss, {1, 2, 3})
Enum.take_random(100..999, 3)
# => [680, 127, 622]
The random values returned by Enum.random
and the Erlang's rand
module are not cryptographically secure. Do not use them to generate cryptographical keys, passwords, or nonces. For this use case, there's Erlang's :crypto.strong_rand_bytes/1
.