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 6 7 8 9 10 | [ 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 6 7 8 9 10 | [ 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.
1 2 | [ :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.
1 2 3 4 5 6 7 8 | [].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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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”.
1 2 3 4 5 6 7 8 | 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