我有这样的哈希:
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
没有密钥v
,h[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}