Feature #12817
openConsider adding method .sample() on class Hash (if this was not yet proposed)
Description
Hello ruby core team and all who may read this.
Some time ago, I think in ruby 1.8.x, the method .sample() was added
to class Array. I think before this addition, it was a bit more cumbersome
to get a random entry from an array - I remember having used .shuffle.first
or something like that, until I noticed that .sample() existed. (I do not
remember if the first 1.8.x release that I used had it; I started with
ruby in perhaps late 2003 or 2004 or so).
Anyway. This method is very nice for class Array if we want one or more
random entries.
So today I wondered why class Hash does not have a sample method.
Are the use cases so different to class Array? The method .sample()
on class Array will return a random element, right? Well, hashes
also have elements, key-value settings.
So my proposal is to add either or all of these methods to class
Hash:
hash.sample
In order to illustrate what this should do, here is pseudo-code:
hash = { cat: 'Tom', mouse: 'Jerry' }
hash.sample # => 'Tom'
(Sorry, I loved Tom and Jerry when I was a kid so I use this as
my main Hash a lot.)
Note that in the above Hash, you could also create a new sub-hash
such as:
hash = { cat: 'Tom', mouse: 'Jerry' }
hash.sample # => { :cat => 'Tom' }
I don't mind either way, both is fine by me. The "will return a
hash" is probably more consistent because class Array .sample()
method will return an Array. So I guess that is the better
variant.
The main thing for me is that a method .sample could be used on
class Hash, similar to class Array. If it looks like a duck and
quacks like a duck ... it may be a cat pretending to be a duck!
Or it may be a duck indeed. But both are animals anyway.
Admittedly the above .sample() for hash is sort of more a method
like .random() - that is, we return a random element. But this
is how class Array's sample() already works too, right?
Here is the documentation:
https://ruby-doc.org/core-2.2.0/Array.html#method-i-sample
The documentation for .sample() states:
"Choose a random element or n random elements from the array."
So you could also actually name it .random perhaps but maybe
.sample() was a better name, I have no idea myself. It probably
is now established and used by ruby hackers so we can stick to
.sample() anyway.
That documentation also has an example, which I translated or
simplified a bit:
array = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
array.sample # => 7
array.sample(2) # => [6, 5]
I assume that for the most similar behaviour, I should picture
something like this, also returning a "smaller" random representation
of the given Hash:
hash = { cat: 'Tom', mouse: 'Jerry', duck: 'Timmy', horse: 'Pete' }
hash.sample(2) # => { duck: 'Timmy', horse: 'Pete' }
hash.sample(2) # => { cat: 'Tom', horse: 'Pete' }
(I guess hash.random(2) and array.random(2) might also be used to
illustrate the concept, but it should be the same name to avoid
confusion; since class Array already has .sample(), I would like
to suggest this for class Hash).
Do note that the above is already easily possible - just obtain
all keys from hash, then apply .sample(), then query the hash
itself again to return a hash.
Example again showing only 2 sample results:
hash = { cat: 'Tom', mouse: 'Jerry', duck: 'Timmy', horse: 'Pete' }
keys = hash.keys
sample = keys.sample(2) # => [:duck, :cat]
values = hash.values_at(*sample) # => ["Timmy", "Tom"]
Hash[*sample.zip(values).flatten] # => {:duck=>"Timmy", :cat=>"Tom"}
So this is already possible but a bit cumbersome in my opinion. With
a .sample() method this would be easier to use and re-use.
No idea if this is a good suggestion or something that can not be
added for any reason but I wanted to propose it at the least, in the
event that nobody else has done so. If it was already proposed before,
sorry for not finding it; feel free to link it into the other
proposal and close the request here in that latter case.
Thank you for reading - may ruby save many more ducks in the
future.