I\'m looking to extract n random key-value pairs from a hash.
Reading the top ranked answers, I'd go with it depends:
If you want to sample only one element from the hash, @Ivaylo Strandjev's solution only relies on hash lookup and Array#sample
:
hsh[hsh.keys.sample]
To sample multiple hash elements, @sawa's answer leverages Array#to_h
:
hsh.to_a.sample(n).to_h
Note that, as @cadlac mentions, hsh.to_a.sample.to_h
won't work as expected. It will raise
TypeError: wrong element type String at 0 (expected array)
because Array#sample
in this case returns just the element array, and not the array containing the element array.
A workaround is his solution, providing an n = 1
as an argument:
hsh.to_a.sample(1).to_h
PS: not looking for upvotes, only adding it as an explanation for people newer to Ruby.
One way to accomplish this:
rank_hash = {"Listen" => 1, "Download" => 60, "Share" => 150, "Purchase" => 700 }
rank_array = rank_hash.to_a
Than call this to get random array sample of the k/v pair:
rank_array[rand(0..3)]
or this to not hard-code the arrays length:
rank_array[rand(0..(rank_array.length) -1)]
Example:
["Download", 60]
Hash[original_hash.to_a.sample(n)]
For Ruby 2.1,
original_hash.to_a.sample(n).to_h
I don't know of such method. Still you can do something like:
h[h.keys.sample]
If you need to sample more than one element the code will have to be a bit more complicated.
EDIT: to get key value pairs instead of only the value you can do something like:
keys_sample = h.keys.sample(n)
keys_sample.zip(keys_sample.map{|k| h[k])
If your sample has only one element, you could use this:
sample = h.keys.sample
h.select { |k,v| k == sample }
Or if your sample contains more than one element, use this:
n = 2
sample = h.keys.sample(n)
h.select { |k,v| sample.include?(k) }