0

After checking this Ruby convert array to nested hash and other sites I am not able to achieve the following convertion:

I have this:

{"a"=>"text"}
{"b"=>{"x"=>"hola"}}
{"b"=>{"y"=>"pto"}

}

and I want to obtain:

{"a"=>text,
    b=>{"x" => "hola",
        "y" => "pto"    
    }
}

Until now the code seems like this:

tm =[[["a"],"text"],[["b","x"],"hola"],[["b","y"],"pto"]]

q = {}
tm.each do |l|
    q = l[0].reverse.inject(l[1]) { |p, n| { n => p } }
    i += 1

end

I tried with merge, but it overwrites the keys!. I tried also this How can I merge two hashes without overwritten duplicate keys in Ruby? but it keeps overwritting.

Update:

How can I do it for an undefined nested hash (level) ? hash[key1][key2][key3]... = "value"

{"a"=>"text"},
    {"b"=>{"x"=>"hola"},
    {"b"=>{"y"=>"pto"},
    {"c"=>{"g"=>{"k" => "test1"}},
    ...
}
Community
  • 1
  • 1
karlihnos
  • 415
  • 1
  • 7
  • 22
  • The one who downvoted has no reasons. No research effort? I think my question is much better than this http://stackoverflow.com/questions/8415240/merge-ruby-hash. ANd this question has many up votes. Next time don't do it for fun. – karlihnos Aug 28 '15 at 12:27

2 Answers2

3

You could use merge with a block to tell Ruby how to handle duplicate keys:

a = {"a"=>"text"}
b = {"b"=>{"x"=>"hola"}}
c = {"b"=>{"y"=>"pto"}}

a.merge(b).merge(c) { |key, left, right| left.merge(right) }
#=> {"a"=>"text", "b"=>{"x"=>"hola", "y"=>"pto"}}
spickermann
  • 100,941
  • 9
  • 101
  • 131
  • This works very good, but I forgot to say that I need this for undefined nested level. This works for maximum 2 levels. I update my question. – karlihnos Aug 28 '15 at 11:22
1

For Rails there is the deep_merge function for ActiveSupport that does exactly what you ask for.

You can implement the same for yourself as follows:

class ::Hash
    def deep_merge(second)
        merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
        self.merge(second, &merger)
    end
end

Now,

h1 = {"a"=>"text"}
h2 = {"b"=>{"x"=>"hola"}}
h3 = {"b"=>{"y"=>"pto"}}
h1.deep_merge(h2).deep_merge(h3)
# => {"a"=>"text", "b"=>{"x"=>"hola", "y"=>"pto"}}
shivam
  • 16,048
  • 3
  • 56
  • 71