如何转换ruby哈希以使值成为指向一组旧密钥的键?

Non*_*ona 4 ruby hash

我有这样的哈希:

t={"4nM"=>"Triangle", "I40"=>"Triangle", "123"=>"Square"}
Run Code Online (Sandbox Code Playgroud)

我想把它变成哈希,如:

{"Triangle" => ["4nM", "I40"], "Square" => ["123"]}
Run Code Online (Sandbox Code Playgroud)

做这个的最好方式是什么?

我开始,group_by但然后代码变得有点复杂....

这就是我做的:

t.group_by { |k, v| v }.map { |type, group| {type => group.flatten.reject { |x| x == type } } }
Run Code Online (Sandbox Code Playgroud)

Car*_*and 6

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

h.each_with_object({}) { |(k,v),h| (h[v] ||= []) << k }
  #=> {"Triangle"=>["4nM", "I40"], "Square"=>["123"]}
Run Code Online (Sandbox Code Playgroud)

表达方式

(h[v] ||= []) << k
Run Code Online (Sandbox Code Playgroud)

扩展到

(h[v] = h[v] || []) << k
Run Code Online (Sandbox Code Playgroud)

如果h有一个键v,h[k]将是真实的,所以上面的表达式减少到了

(h[v] = h[v]) << k
Run Code Online (Sandbox Code Playgroud)

然后

h[v] << k
Run Code Online (Sandbox Code Playgroud)

如果h没有一个键v,h[k] #=> nil,所以上面的表达式简化为

(h[v] = []) << k
Run Code Online (Sandbox Code Playgroud)

导致

h[v] #=> [k]
Run Code Online (Sandbox Code Playgroud)

或者,我们可以写

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

有关使用块返回哈希中不存在的键的默认值的说明,请参阅Hash :: new.

  • 更短:`t.each_with_object(Hash.new {[]}){|(k,v),h | h [v] << = k}` (2认同)