9

I learned from Access nested hash element specified by an array of keys)

that if i have a array

array = ['person', 'age']

and I have a nested hash

hash = {:person => {:age => 30, :name => 'tom'}}

I can get the value of of age by using

array.inject(hash, :fetch)

But How would I then set the value of :age to 40 with the array of keys?

Community
  • 1
  • 1
seanrclayton
  • 157
  • 1
  • 7

3 Answers3

11

You can get the hash that contains the last key in the array (by removing the last element), then set the key's value:

array.map!(&:to_sym) # make sure keys are symbols

key = array.pop
array.inject(hash, :fetch)[key] = 40

hash # => {:person=>{:age=>40, :name=>"tom"}}

If you don't want to modify the array you can use .last and [0...-1]:

keys = array.map(&:to_sym)

key = keys.last
keys[0...-1].inject(hash, :fetch)[key] = 40
August
  • 12,410
  • 3
  • 35
  • 51
  • @CarySwoveland Thanks, I overlooked that. I also added an alternate solution if it's important to preserve the array. – August Jan 29 '15 at 19:21
  • Still not testing! If you don't want to modify `array`, `keys = array.map(&:to_sym); key = keys.last...`. (Ah, yes, it's `pop`. I had `shift` on the brain.) – Cary Swoveland Jan 29 '15 at 19:25
0

You could use recursion:

def set_hash_value(h, array, value)
  curr_key = array.first.to_sym
  case array.size
  when 1 then h[curr_key] = value
  else set_hash_value(h[curr_key], array[1..-1], value)
  end
  h
end

set_hash_value(hash, array, 40)
  #=> {:person=>{:age=>40, :name=>"tom"}}
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
0

You can consider using the set method from the rodash gem in order to set a deeply nested value into a hash.

require 'rodash'

hash = { person: { age: 30, name: 'tom' } }

key = [:person, :age]
value = 40

Rodash.set(hash, key, value)

hash
# => {:person=>{:age=>40, :name=>"tom"}}
Marian13
  • 7,740
  • 2
  • 47
  • 51