Is there an equivalent to `Array::sample` for hashes?

前端 未结 5 1675
终归单人心
终归单人心 2020-12-14 14:26

I\'m looking to extract n random key-value pairs from a hash.

相关标签:
5条回答
  • 2020-12-14 15:02

    Reading the top ranked answers, I'd go with it depends:

    1. 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]
      
    2. 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.

    0 讨论(0)
  • 2020-12-14 15:05

    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]
    
    0 讨论(0)
  • 2020-12-14 15:09
    Hash[original_hash.to_a.sample(n)]
    

    For Ruby 2.1,

    original_hash.to_a.sample(n).to_h
    
    0 讨论(0)
  • 2020-12-14 15:09

    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])
    
    0 讨论(0)
  • 2020-12-14 15:11

    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) }
    
    0 讨论(0)
提交回复
热议问题