it-swarm.com.de

Umkehren eines Hash in Ruby

Wie würde ich die Elemente im Hash umkehren, die gleichen Werte und Schlüssel beibehalten, aber ihre Reihenfolge im Hash umkehren?.

So wie:

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

Und konvertiere das zu:

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

Oder vielleicht könnte ich eine each-Schleife rückwärts laufen lassen, beginnend mit dem letzten Element im Hash und nicht mit dem ersten? 

27
slyv

Sie können den Hash in ein Array konvertieren, umkehren und ihn anschließend wieder in einen Hash konvertieren:

reversed_h = Hash[h.to_a.reverse]

Hash#to_a gibt Ihnen ein Array von Arrays, die inneren Arrays sind einfache [key,value]-Paare, dann kehren Sie dieses Array mit Array#reverse um, und Hash[] wandelt die [key,value]-Paare zurück in einen Hash.

Ruby 2.1 fügt eine Array#to_h -Methode hinzu, so dass Sie jetzt sagen können:

reversed_h = h.to_a.reverse.to_h
61
mu is too short

In Ruby 2.1+ können Sie reverse_each und to_h kombinieren:

{foo: 1, bar: 2}.reverse_each.to_h
#=> {:bar=>2, :foo=>1}
6
Stefan
hash = { "4" => "happiness", "10" => "cool", "lala" => "54", "1" => "spider" }
reversed_hash = Hash[hash.to_a.reverse]
4
aromero
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"}

Dies hinterlässt jedoch einen schlechten Geschmack (genau wie die anderen Antworten, die genau wie diese funktionieren). Wenn Sie dies tun müssen, kann dies ein Hinweis darauf sein, dass ein Hash nicht die beste Wahl war.

4
steenslag
reversed_h = Hash[h.to_a.collect(&:reverse)]
2
Minqi Pan

wenn nötig:

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

zu:

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

können:

h={};hash.to_a.each{|e|h[e[1]]||=[];h[e[1]]<<e[0]};h
0
dmitryck

In reinem Ruby können Sie dies mit hash.map(&:reverse).to_h oder hash.reverse_each.to_h tun

In Rails können Sie dies mit hash.invert tun.

0
khaled_gomaa

Alternativ können Sie reduce und merge verwenden, um das Element vor einem neuen Hash hinzuzufügen:

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

aber das ist verrückt: D

0

In Ruby 1.8.7 ist dokumentiert, dass die Reihenfolge der Elemente in einem Hash nicht unter unserer Kontrolle steht. Daher funktioniert keine der oben genannten Methoden. In Ruby 1.9.3 funktionieren die Dinge und werden in der Art und Weise dokumentiert, auf die sich die anderen Antworten beziehen.

 $ irb1.8 
 h = {"4" => "Glück", "10" => "cool", "lala" => "54", "1" => "Spinne"}
 Hash [h.to_a (). Reverse ()] 
 => {"Lala" => "54", "1" => "Spinne", "10" => "cool", "4" => "Glück"} 
 quit 
 $ irb1.9.1 
 h = {"4" => "Glück", "10" => "cool", "lala" => "54", "1" => "Spinne"} 
 Hash [h.to_a (). Reverse ()] 
 => {"1" => "Spinne", "lala" => "54", "10 "=>" cool "," 4 "=>" Glück "} 

Der Ruby 1.8.7-Weg war für mich so fest verankert, dass ich die Frage lange Zeit falsch verstanden hatte. Ich dachte, es forderte einen Weg nach Hash # invert : dh den Hash so umzuwandeln, dass der Bereich der Domäne zugeordnet wird. Bei dieser Methode werden Duplikate verworfen. Luís Ramalho bietet eine Methode das tut es nicht, aber es ist etwas klobig. Das ist etwas kürzer:

 $ irb 
 def invertWithDuplicates (original) 
 inverse = Hash.new () {| Hash, Schlüssel | Hash [Schlüssel] = []; } 
 original.each_pair () {| key, Wert | inverse [value] .Push (Taste); } 
 return invers 
 end 
 h = {"4" => "happiness", "10" => "cool", "lala" => "54", "1" => "cool"} 
invertWithDuplicates (h) 
 => {"Glück" => ["4"], "cool" => ["1", "10"], "54" => ["lala"]} 

Es tut mir leid, dass Sie sich vom beabsichtigten Thema des OP entfernen, obwohl ich sage, dass dies zum Titel des Posts "Reverse a hash in Ruby" passt.

0
Martin Dorey