Project

General

Profile

Feature #12817

Consider adding method .sample() on class Hash (if this was not yet proposed)

Added by shevegen (Robert A. Heiler) almost 3 years ago. Updated almost 3 years ago.

Status:
Open
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:77507]

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.

History

Updated by shyouhei (Shyouhei Urabe) almost 3 years ago

Hash#sample was proposed by you, Robert. https://bugs.ruby-lang.org/issues/12586

Is this your second challenge? That's completely OK but can I close the former one for housekeeping?

Also available in: Atom PDF