2011-10-04 141 views
4

有什麼快速的方法來獲得給定散列的(隨機)排列?例如用陣列我可以使用sample方法如Ruby哈希排列

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] 

用於散列我可以使用散列密鑰的相同的方法,並建立一個新的散列與

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"} 

但這是如此難看。有沒有可以避免所有代碼的散列的「樣本」方法?

更新正如@Michael Kohl在評論中指出的,這個問題僅對ruby 1.9.x有意義。由於在1.8.x中哈希是無序的,所以沒有辦法做到這一點。

+1

這是什麼意思?在1.8哈希是無序的,並在1.9按插入順序排序。 –

+1

@Michael:看起來他正在使用1.9,因此'h.each'具有明確定義的順序,所以對Hash進行洗牌是有道理的。 –

+0

@MichaelKohl這只是一個好奇心。此外,即使使用1.8無序哈希來調用該方法,每次都會返回不同的順序,而不是確定性和固定順序。把它看作是散列類的洗牌。 – Fabio

回答

9

畝的輕微細化太短的回答是:

h = Hash[h.to_a.shuffle] 
+1

+1值得完善。 –

4

只需添加一個to_aHash[]你的陣列版本,以獲得一個哈希版本:

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

例如:

>> 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"} 
+0

非常好,謝謝。 – Fabio

+1

'h = Hash [h.to_a.shuffle]' – steenslag

+1

@steenslag:這看起來像一個答案(和一個好的答案),你應該把它放下來。 –

0

你真的需要洗牌還是隻需要一種方法來訪問/迭代隨機密鑰?

否則,說不定更便宜的解決辦法是重新洗牌的哈希鍵和訪問基於這些哈希鍵的排列您的項目

h = your_hash 
shuffled_hash_keys = hash.keys.shuffle 

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

我相信,(但需要有一個基準的證明),其這樣可以避免構建全新散列的需要/成本,並且如果您有大散列(您只需支付數組排列的代價),則可能會更有效。