web-dev-qa-db-fra.com

Inverser un hash en Ruby

Comment pourrais-je inverser les éléments du hachage en conservant les mêmes valeurs et clés, mais en inversant leur ordre dans le hachage?.

Ainsi:

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

Et convertir cela en:

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

Ou peut-être pourrais-je exécuter une boucle each en arrière, en commençant par le dernier élément du hachage, plutôt que par le premier? 

27
slyv

Vous pouvez convertir le hachage en tableau, l'inverser, puis le reconvertir en hachage:

reversed_h = Hash[h.to_a.reverse]

Hash#to_a vous donne un tableau de tableaux, les tableaux internes sont de simples paires [key,value], puis vous inversez ce tableau en utilisant Array#reverse et Hash[] convertit les paires [key,value] en un hachage.

Ruby 2.1 ajoute une méthode Array#to_h afin que vous puissiez maintenant dire:

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

Dans Ruby 2.1+, vous pouvez combiner reverse_each et to_h :

{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"}

Mais cela laisse un mauvais goût (tout comme les autres réponses, qui fonctionnent bien comme celle-ci). Si vous devez le faire, cela pourrait indiquer qu’un hachage n’est pas le meilleur choix.

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

si besoin:

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

à:

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

pouvez:

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

En Ruby pur, vous pouvez le faire par hash.map(&:reverse).to_h ou hash.reverse_each.to_h

Dans Rails, vous pouvez le faire par hash.invert

0
khaled_gomaa

Vous pouvez également utiliser reduce et merge pour ajouter l'élément à l'avant d'un nouveau hachage:

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

mais c'est fou: D

0

Dans Ruby 1.8.7 , il est établi que l’ordre des éléments d’un hachage n’est pas sous notre contrôle; aucune des méthodes ci-dessus ne fonctionne. Dans Ruby 1.9.3 , les choses fonctionnent et sont documentées de la même manière que les autres réponses.

 $ irb1.8 
 h = {"4" => "bonheur", "10" => "cool", "lala" => "54", "1" => "araignée"}
 Hash [h.to_a (). Reverse ()] 
 => {"Lala" => "54", "1" => "araignée", "10" => "cool", "4" => "bonheur"} 
 quit 
 $ irb1.9.1 
 h = {"4" => "bonheur", "10" => "cool", "lala" => "54", "1" => "spider"} 
 Hash [h.to_a (). Reverse ()] 
 => {"1" => "spider", "lala" => "54", "10 "=>" cool "," 4 "=>" bonheur "} 

La façon dont Ruby 1.8.7 était si profondément enracinée pour moi que j'ai mal compris la question pendant un bon bout de temps. Je pensais que cela demandait un moyen de Hash # invert : c'est-à-dire de transformer le hachage de telle sorte que la plage mappe vers le domaine. Cette méthode élimine les doublons. Luís Ramalho propose une méthode ça ne fonctionne pas, mais c'est un peu maladroit. C'est un peu plus court:

 $ irb 
 def invertWithDuplicates (original) 
 inverse = Hash.new () {| hash, clé | hash [clé] = []; } 
 original.each_pair () {| clé, valeur | inverse [valeur] .Push (clé); } 
 return inverse 
 end 
 h = {"4" => "bonheur", "10" => "cool", "lala" => "54", "1" => "cool"} 
invertWithDuplicates (h) 
 => {"happiness" => ["4"], "cool" => ["1", "10"], "54" => ["lala"]} 

Désolé de m'éloigner du sujet visé par le PO, bien que je soutienne que cela correspond au titre du message "Inverser un hachage dans Ruby".

0
Martin Dorey