开发者

Ruby hash permutation

开发者 https://www.devze.com 2023-04-10 09:16 出处:网络
Is there any quick way to get a (random) permutation of a given hash? For example with arrays I can use the sample method as in

Is there any quick way to get a (random) permutation of a given hash? For example with arrays I can use the sample method as in

ruby-1.9.2-p180 :031 > a = (1..5).to_a
 => [1, 2, 3, 4, 5] 
ruby-1.9.2-p180 :032 > a.sample(a.length)
 => [3, 5, 1, 2, 4] 

For hashes I can use the same method on hash keys and build a new hash with

ruby-1.9.2-p180 :036 > h = { 1 => 'a', 2 => 'b', 3 => 'c' }
 => {1=>"a", 2=>"b", 3=>"c"} 
ruby-1.9.2-p180 :037 > h.keys.sample(h.length).inject({}) { |h2, k| h2[k] = h[k]; h2 }
 => {3=>"c", 2=>"b", 1=>"a"} 

but this is so ugly. Is there any 'sample' method for hashes which can avoid all that code?

Update As pointed out by @Michael Kohl in comments, this question is meaningful only开发者_如何转开发 for ruby 1.9.x. Since in 1.8.x Hash are unordered there is no way to do that.


A slight refinement of mu is too short's answer:

h = Hash[h.to_a.shuffle]


Just add a to_a and Hash[] to your array version to get a Hash version:

h = Hash[h.to_a.sample(h.length)]

For example:

>> h = { 1 => 'a', 2 => 'b', 3 => 'c' }
=> {1=>"a", 2=>"b", 3=>"c"}
>> h = Hash[h.to_a.sample(h.length)]
=> {2=>"b", 1=>"a", 3=>"c"}


Do you really need to shuffle or do you just need a way to access/iterate on a random key ?

Otherwise, a maybe less expensive solution would be to shuffle the hash keys and access your items based on the permutation of those hash keys

h = your_hash
shuffled_hash_keys = hash.keys.shuffle

shuffled_hash_keys.each do |key|
  # do something with h[key]
end

I believe (but would need a proof with a benchmark) that this avoids the need/cost to build a brand new hash and is probably more efficient if you have big hashes (you only need to pay the cost of an array permutation)

0

精彩评论

暂无评论...
验证码 换一张
取 消