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