0

For accessing a nested value in the following hash:

 y={"en"=>
  {"slogan"=>"Sky",
   "countries"=>{"AW"=>"Aruba", "AF"=>"Afghanistan"},
   "op_modes"=>{"classic"=>{0=>"Alert", 10=>"Auto"}},
   "reg"=>
    {"headline"=>"Online",
     "key1"=>"value1",
     "key2"=>"value2",
     "key3"=>"value3",
     "key4"=>"value4",
     "installation"=>
      {"text1"=>
        "'3.2 Tomorrow:'\n",
       "gridtypes"=>{"tt"=>"TT", "tn-s"=>"TN-S"}}}}}

I have this (found the way in this post):

key = 'en.countries.AW'
ki = key.split('.')
fg = ki.inject(y) {|h, k| h[k]} # => "Aruba"

How can I assign value "x value" when a key does not exist? How can I create a new key (any depth) with this value?

I tried something like this but there is an error:

key = 'en.countries.new_one'

if fg.nil?
  ki.inject(y) do |h, k|
    h[k] = "x value"
  end
end

Update:

The answer of sawa helped me a lot but I did a little modification to reach unlimited levels (depth).

key = 'en.countries.new_one'

key.split(".").inject(y) do |h, k| 
  h.key?(k) ? h[k] : h[k] = {} 
end
Community
  • 1
  • 1
karlihnos
  • 415
  • 1
  • 7
  • 22

2 Answers2

3
key = 'en.countries.new_one'

key.split(".").inject(y) do |h, k| 
  h.key?(k) ? h[k] : h[k] = "x value" 
end
sawa
  • 165,429
  • 45
  • 277
  • 381
  • Thxs for your effort, this works, however, when adding a totally new key: 'en.new_key.level' it does not work. – karlihnos Sep 23 '15 at 08:06
  • There is no way to make that work. If the value for an intermediate level `"new_key"` is the string `"x value"`, then there is no sense for looking deeper. – sawa Sep 23 '15 at 08:07
  • Well, the point is that I have a yaml data and that is why it is important to look deeper or maintain the hierarchy. I'm comparing two languages (keys). – karlihnos Sep 23 '15 at 08:10
  • Whatever your point is, it does not make sense to consider "the value for the key `"level"` within the string `"x value"`". – sawa Sep 23 '15 at 08:12
  • Sorry, but I do not get why it does not make sense. For YAML data the hierarchy is very important. And the insertion of new keys must keep the hierarchy, otherwise it wont work the translations. – karlihnos Sep 23 '15 at 08:20
  • Then tell me: What is "the value for the key `"level"` in the string `"x value"`"? – sawa Sep 23 '15 at 08:21
  • Let's say I add a new key to english, en.new_key.level = "Welcome", for spanish this new key must be added like this, es.new_key.level = "Bienvenidos". For looking these translations I have to follow the complete path (language.new_key.level). The "x value" is just a random value I gave it. – karlihnos Sep 23 '15 at 08:25
  • "The `"x value"` is just a random value I gave it"--You didn't write so in the question. And whatever other string it is, it does not make a difference. – sawa Sep 23 '15 at 08:27
3

The key to getting a hash to work with inject, is to remember that on each iteration, the hash being built needs to be the item returned.

So:

'en.countries.new_one'.split('.').inject({}) do |hash, key| 
  hash[key] ||= "some value" 
  hash
end

Assigning a value to a hash key returns the value being assigned, not the hash. So you have to explicitly add to the end of the iteration code, a call that returns the hash being built.

ReggieB
  • 8,100
  • 3
  • 38
  • 46
  • That will keep returning the original `hash`. Assignment can only (correctly) happen at the deepest level (since the value is a string), so you don't need the explicit `hash` anyway. – sawa Sep 23 '15 at 08:08