如何转动红宝石哈希,以使该值成为指向一组旧键的钥匙



我有这样的哈希:

t={"4nM"=>"Triangle", "I40"=>"Triangle", "123"=>"Square"}

,我想将其变成像:

的哈希
{"Triangle" => ["4nM", "I40"], "Square" => ["123"]}

最好的方法是什么?

我从group_by开始,但是随后代码有点令人费解。

这就是我所做的:

t.group_by { |k, v| v }.map { |type, group| {type => group.flatten.reject { |x| x == type } } }
h = { "4nM"=>"Triangle", "I40"=>"Triangle", "123"=>"Square" }
h.each_with_object({}) { |(k,v),h| (h[v] ||= []) << k }
  #=> {"Triangle"=>["4nM", "I40"], "Square"=>["123"]}

表达式

(h[v] ||= []) << k

扩展到

(h[v] = h[v] || []) << k

如果h具有键v,则h[k]将是真实的,因此上面的表达式减少到

(h[v] = h[v]) << k

,然后

h[v] << k

如果h没有密钥vh[k] #=> nil,那么上面的表达式将减少为

(h[v] = []) << k

导致

h[v] #=> [k]

另外,我们可以写

h.each_with_object(Hash.new { |h,k| h[k] = [] }) { |(k,v),h| h[v] << k }
  #=> {"Triangle"=>["4nM", "I40"], "Square"=>["123"]}

请参阅HASH ::新的,以说明使用块用于返回哈希中不存在的键的默认值的使用。

这是我可以写的最短:

t.group_by(&:last).map{|k,v|[k,v.map(&:first)]}.to_h

仍然比@Cary Swoveland的答案长4个字符。

请注意,在Rails中,Hash#transform_values使其更容易:

t.group_by{|_,v| v }.transform_values{|v| v.map(&:first) }

您可以通过这样做

将其切成一点
t.group_by {|k,v| v}.map{|k,v| {k => v.map(&:first)}}

但是您的原始实现已经很简洁。

t={"4nM"=>"Triangle", "I40"=>"Triangle", "123"=>"Square"}
h = Hash.new{[]}
t.each{|k,v| h[v] <<= k} 

最新更新