Ruby哈希排列

4
有没有一种快速的方法来获取给定哈希值的(随机)排列?例如,对于数组,我可以使用 sample 方法,如下所示:
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中则按插入顺序排序。 - Michael Kohl
1
@Michael:看起来他正在使用1.9版本,因此对哈希进行洗牌是有意义的,因为h.each确实具有明确定义的顺序。 - mu is too short
@MichaelKohl 这只是一种好奇心。此外,即使使用1.8无序哈希,调用该方法每次都会返回不同的顺序,而不是确定性和固定顺序。将其视为哈希类的洗牌。 - Fabio
@Fabio 你测试过了吗?我认为被接受的答案在 Ruby 1.8.6 中不会产生任何影响。 - steenslag
@steenslag 我已经在1.9.2中测试了这两种方法,它们都可以工作。然而,在1.8.x中它们都无法工作,我刚刚尝试使用1.8.7-p334的rvm。示例方法在1.8.x中不可用,shuffle可以工作,但正如你所说,它在构建新哈希时没有任何效果。 - Fabio
1
@muistooshort:当然,我在我的评论中写了那个。但是由于哈希通常是通过键查找的...无论如何,智识好奇心至少和许多其他论点一样好 :-) - Michael Kohl
3个回答

9
mu的回答有一点不够完美,稍微改进一下如下:

mu的回答稍作修改:

h = Hash[h.to_a.shuffle]

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

1
@steenslag:看起来像是一个答案(而且是个好答案),你应该把它写下来。 - mu is too short

0
你真的需要洗牌吗?还是只需要一种访问/迭代随机键的方法?
否则,可能更便宜的解决方案是洗牌哈希键并根据这些哈希键的排列访问你的项目。
h = your_hash
shuffled_hash_keys = hash.keys.shuffle

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

我相信(但需要通过基准测试来证明)这可以避免构建全新哈希的需求和成本,如果你有大型哈希表,这可能更加高效(你只需要支付数组排列的成本)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接