2010-06-21 9 views
3

Disons que j'ai un imbriquée Hash h arbitraire profonde:Comment remplacer toutes les valeurs d'un hachage par une nouvelle valeur?

h = { 
    :foo => { :bar => 1 }, 
    :baz => 10, 
    :quux => { :swozz => {:muux => 1000}, :grimel => 200 } 
    # ... 
} 

Et disons que j'ai une classe C définie comme:

class C 
    attr_accessor :dict 
end 

Comment puis-je remplacer toutes les valeurs imbriquées dans h afin qu'ils sont maintenant C instances avec l'attribut dict défini à cette valeur? Par exemple, dans l'exemple ci-dessus, je vous attendre à avoir quelque chose comme:

h = { 
    :foo => <C @dict={:bar => 1}>, 
    :baz => 10, 
    :quux => <C @dict={:swozz => <C @dict={:muux => 1000}>, :grimel => 200}> 
    # ... 
} 

<C @dict = ...> représente une instance C avec @dict = .... (Notez que dès que vous atteignez une valeur qui est pas imbriqué, vous arrêtez l'enroulant dans C cas.)

Répondre

1
def convert_hash(h) 
    h.keys.each do |k| 
    if h[k].is_a? Hash 
     c = C.new 
     c.dict = convert_hash(h[k]) 
     h[k] = c 
    end 
    end 
    h 
end 

Si nous remplaçons inspect dans C pour obtenir une sortie plus amicale comme ceci:

def inspect 
    "<C @dict=#{dict.inspect}>" 
end 

puis exécutez votre exemple h cela donne:

puts convert_hash(h).inspect 

{:baz=>10, :quux=><C @dict={:grimel=>200, 
:swozz=><C @dict={:muux=>1000}>}>, :foo=><C @dict={:bar=>1}>} 

en outre, si vous ajoutez un initialize méthode pour C pour la mise en dict:

def initialize(d=nil) 
    self.dict = d 
end 

alors vous pouvez réduire les 3 lignes au milieu de convert_hash juste h[k] = C.new(convert_hash_h[k])

+0

Vous pouvez le faire '' h.tap ... afin que vous n'avez pas à retourner h à la fin (Ruby 1.9 seulement). –

+0

@John pour ce faire dois-je dire 'h.tap do | h | h.keys.each faire | k | ... ou peut-il être écrit plus élégamment? – mikej

+0

C'est à peu près tout, ouais. Tap est plus utile lorsque vous l'injectez au milieu d'un flux de méthodes chaînées afin de ne pas interrompre le "flux". –

1
class C 
    attr_accessor :dict 

    def initialize(dict) 
    self.dict = dict 
    end 
end 

class Object 
    def convert_to_dict 
    C.new(self) 
    end 
end 

class Hash 
    def convert_to_dict 
    Hash[map {|k, v| [k, v.convert_to_dict] }] 
    end 
end 

p h.convert_to_dict 
# => { 
# => :foo => { 
# =>  :bar => #<C:0x13adc18 @dict=1> 
# => }, 
# => :baz => #<C:0x13adba0 @dict=10>, 
# => :quux => { 
# =>  :swozz => { 
# =>  :muux => #<C:0x13adac8 @dict=1000> 
# =>  }, 
# =>  :grimel => #<C:0x13ada50 @dict=200> 
# => } 
# => }