Today’s Ruby Tuesday is on Array#sample.
Array#sample
has a couple of different forms it can take.
The first form it can take is a version where no arguments are passed; in this case it returns a random element from the array it was called on, or nil
if the array is empty.
[1, 2, 3, 4, 5].sample
# => 4
[1, 2, 3, 4, 5].sample
# => 1
[1, 2, 3, 4, 5].sample
# => 2
[].sample
# => nil
[:heart, :diamond, :club, :spade].sample
# => :club
Array#sample
can also take as its argument a count of the number of random items to be returned.
[1, 2, 3, 4, 5].sample 2
# => [1, 2]
[1, 2, 3, 4, 5].sample 2
# => [2, 1]
[1, 2, 3, 4, 5].sample 2
# => [1, 3]
[1, 2, 3, 4, 5].sample 2
# => [3, 5]
[1, 2, 3, 4, 5].sample 2
# => [5, 2]
If the argument to the count is greater than, or equal to, the number of items in the array, then the array is returned.
[:heart, :diamond, :club, :spade].sample 6
# => [:heart, :diamond, :spade, :club]
This has two subtle but important consequences. First if we call sample with a count on an empty array, an empty array is returned, instead of a nil
like we would get back if we just call Array#sample
with no count argument. This includes calling Array#sample
with a count of zero on an empty array.
[].sample
# => nil
[].sample 0
# => []
[].sample 1
# => []
[].sample 3
# => []
Second, it shows that as we sample the array, we are not going to get duplicate elements, unless they were in the array to being with.
On both of these forms, a random number generator can also be passed. This can give us a repeatable generation sequence as we can prime the generator with a given seed.
generatorA = Random.new 1
# => #<Random:0x007f86c3925878>
(1..100).to_a.sample(random: generatorA)
# => 38
(1..100).to_a.sample(random: generatorA)
# => 13
(1..100).to_a.sample(random: generatorA)
# => 73
generatorB = Random.new 1
# => #<Random:0x007f86c497dd10>
(1..100).to_a.sample(random: generatorB)
# => 38
(1..100).to_a.sample(random: generatorB)
# => 13
(1..100).to_a.sample(random: generatorB)
# => 73
(1..100).to_a.sample(random: generatorB)
# => 10
(1..100).to_a.sample(random: generatorA)
# => 10
(1..100).to_a.sample(4, random: generatorA)
# => [76, 6, 82, 66]
(1..100).to_a.sample(4, random: generatorA)
# => [17, 2, 79, 74]
(1..100).to_a.sample(4, random: generatorB)
# => [76, 6, 82, 66]
(1..100).to_a.sample(4, random: generatorB)
# => [17, 2, 79, 74]
And if we want to pick a random card from a deck of cards, or even draw a 5 card hand we can use Array#sample
on an array of “playing cards”.
suit = [:heart, :diamond, :club, :spade]
# => [:heart, :diamond, :club, :spade]
rank = [:ace, 2, 3, 4, 5, 6, 7, 8, 9, :jack, :queen, :king]
# => [:ace, 2, 3, 4, 5, 6, 7, 8, 9, :jack, :queen, :king]
suit.product(rank).sample 1
# => [[:heart, :jack]]
suit.product(rank).sample 5
# => [[:club, 2], [:diamond, 2], [:spade, 7], [:club, 8], [:spade, :king]]
–Proctor