Как заменить все значения в хэше новым значением?
Допустим, у меня есть произвольно глубокий вложенный хэш h
:
h = {
:foo => { :bar => 1 },
:baz => 10,
:quux => { :swozz => {:muux => 1000}, :grimel => 200 }
# ...
}
И предположим, что у меня есть класс C
, определенный как:
class C
attr_accessor :dict
end
Как мне заменить все вложенные значения в h
, чтобы они теперь были экземплярами C
с атрибутом dict
, установленным на это значение? Например, в приведенном выше примере я ожидал бы получить что-то вроде:
h = {
:foo => <C @dict={:bar => 1}>,
:baz => 10,
:quux => <C @dict={:swozz => <C @dict={:muux => 1000}>, :grimel => 200}>
# ...
}
Где <C @dict = ...>
представляет собой C
экземпляр с @dict = ...
. (Обратите внимание, что как только вы достигнете значения, которое не является вложенным, вы остановитесь обертывание его в экземпляры C
.)
2 ответа:
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
Если мы переопределяем
inspect
вC
, чтобы дать более дружественный вывод, например:def inspect "<C @dict=#{dict.inspect}>" end
А затем запустите с вашим примером
h
это дает:puts convert_hash(h).inspect {:baz=>10, :quux=><C @dict={:grimel=>200, :swozz=><C @dict={:muux=>1000}>}>, :foo=><C @dict={:bar=>1}>}
Также, если вы добавляете метод
initialize
кC
для установкиdict
:def initialize(d=nil) self.dict = d end
Тогда вы можете уменьшить 3 строки в середине
convert_hash
до простоh[k] = C.new(convert_hash_h[k])
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> # => } # => }