33

我将如何反转散列中的元素,保持相同的值和键,但反转它们在散列中的顺序。

像这样:

{ "4" => "happiness", "10" => "cool", "lala" => "54", "1" => "spider" }

并将其转换为:

{ "1" => "spider", "lala" => "54", "10" => "cool", "4" => "happiness" }

或者,也许我可以each向后运行一个循环,从哈希中的最后一个元素开始,而不是第一个?

4

9 回答 9

68

您可以将哈希转换为数组,将其反转,然后将其转换回哈希:

reversed_h = Hash[h.to_a.reverse]

Hash#to_a给你一个数组数组,内部数组是简单的[key,value]对,然后你使用 反转该数组Array#reverseHash[]并将[key,value]对转换回哈希。

Ruby 2.1 添加了一个Array#to_h方法,因此您现在可以说:

reversed_h = h.to_a.reverse.to_h
于 2012-06-03T22:21:55.447 回答
11

在 Ruby 2.1+ 中,您可以组合reverse_eachto_h

{foo: 1, bar: 2}.reverse_each.to_h
#=> {:bar=>2, :foo=>1}
于 2015-08-16T10:10:20.070 回答
4
hash = { "4" => "happiness", "10" => "cool", "lala" => "54", "1" => "spider" }
reversed_hash = Hash[hash.to_a.reverse]
于 2012-06-03T22:22:10.860 回答
4
h = { "4" => "happiness", "10" => "cool", "lala" => "54", "1" => "spider" }
p Hash[h.reverse_each.map{|e| e}]
#=> {"1"=>"spider", "lala"=>"54", "10"=>"cool", "4"=>"happiness"}

但这会留下不好的味道(就像其他答案一样,就像这个答案一样)。如果您必须这样做,则可能表明哈希不是最佳选择。

于 2012-06-03T23:05:47.283 回答
4

在纯红宝石中,您可以通过hash.map(&:reverse).to_hhash.reverse_each.to_h

在rails中,您可以通过hash.invert

于 2018-06-27T13:34:43.140 回答
1
reversed_h = Hash[h.to_a.collect(&:reverse)]
于 2013-04-16T02:32:30.933 回答
1

或者,您可以使用reduceandmerge将项目添加到新哈希的前面:

hash = { "4" => "happiness", "10" => "cool", "lala" => "54", "1" => "spider" }
hash.reduce({}){ |memo, object| Hash[*object].merge(memo) }

但是,这太疯狂了:D

于 2012-06-03T22:42:31.043 回答
0

Ruby 1.8.7中,哈希中元素的顺序被记录为不受我们控制,因此上述方法都不起作用。在Ruby 1.9.3中,一切正常并以其他答案所依赖的方式记录下来。

$ irb1.8
h = { "4" => "幸福", "10" => "酷", "lala" => "54", "1" => "蜘蛛" }
哈希[h.to_a().reverse()]
=> {“拉拉”=>“54”,“1”=>“蜘蛛”,“10”=>“酷”,“4”=>“幸福”}
退出
$ irb1.9.1
h = { "4" => "幸福", "10" => "酷", "lala" => "54", "1" => "蜘蛛" }
哈希[h.to_a().reverse()]
=>{“1”=>“蜘蛛”、“拉拉”=>“54”、“10”=>“酷”、“4”=>“幸福”}

Ruby 1.8.7 的方式对我来说根深蒂固,以至于我误解了这个问题很长一段时间。我认为它需要一种方法来Hash#invert:即转换散列以使范围映射到域。该方法丢弃重复项。Luís Ramalho 提供了一种没有的方法,但它有点笨拙。这有点短:

$ irb
def invertWithDuplicates(原始)
  逆 = Hash.new() { |散列,键| 哈希[键] = []; }
  original.each_pair() { |键,值| 逆[值].push(key); }
  返回逆
结尾
h = { “4” => “幸福”, “10” => “酷”, “拉拉” => “54”, “1” => “酷” }
invertWithDuplicates(h)
=> {"幸福"=>["4"], "酷"=>["1", "10"], "54"=>["拉拉"]}

很抱歉偏离了 OP 的预期主题,尽管我认为这确实符合帖子的标题“Reverse a hash in Ruby”。

于 2012-12-01T00:49:39.550 回答
0

如果需要:

hash = {:a => :x, :b => :y, :c => :y, :d => :z}

至:

{:x => [:a], :y => [:b, c], :z => [:d] }

能够:

h={};hash.to_a.each{|e|h[e[1]]||=[];h[e[1]]<<e[0]};h
于 2019-02-07T19:24:29.693 回答