The following recursive method should provide the desired results.
def combine_em(arr)
(k1, k2), (v1, v2) = arr.map(&:flatten).transpose
(k1==k2 && v1.is_a?(Hash)) ? { k1=>combine_em([v1, v2]) } :
{}.merge(*arr)
end
arr = [{"base"=>{"floor1"=>{"apt1"=>{"room"=>4}}}},
{"base"=>{"floor1"=>{"apt2"=>{"room"=>6}}}}]
combine_em arr
#=> {"base"=>{"floor1"=>{"apt1"=>{"room"=>4},
# "apt2"=>{"room"=>6}}}}
arr = [{"base"=>{"floor1"=>{"level1"=>{"apt1"=>{"room"=>4}}}}},
{"base"=>{"floor1"=>{"level1"=>{"apt2"=>{"room"=>6}}}}}]
combine_em arr
#=> {"base"=>{"floor1"=>{"level1"=>{"apt1"=>{"room"=>4},
# "apt2"=>{"room"=>6}}}}}
arr = [{"base"=>{"floor1"=>{"apt1"=>{"room"=>4}}}},
{"base"=>{"floor2"=>{"apt1"=>{"room"=>6}}}}]
combine_em arr
#=> {"base"=>{"floor1"=>{"apt1"=>{"room"=>4}},
# "floor2"=>{"apt1"=>{"room"=>6}}}}
arr = [{"base"=>{"floor1"=>{"apt1"=>{"room1"=>4}}}},
{"base"=>{"floor1"=>{"apt1"=>{"room2"=>6}}}}]
combine_em arr
#=> {"base"=>{"floor1"=>{"apt1"=>{"room1"=>4,
# "room2"=>6}}}}
arr = [{"base1"=>{"floor1"=>{"apt1"=>{"room"=>4}}}},
{"base2"=>{"floor2"=>{"apt1"=>{"room"=>6}}}}]
combine_em arr
#=> {"base1"=>{"floor1"=>{"apt1"=>{"room"=>4}}},
# "base2"=>{"floor2"=>{"apt1"=>{"room"=>6}}}}
arr = [{"base"=>{"floor1"=>{"apt1"=>{"room"=>4}}}},
{"base"=>{"floor1"=>{"apt1"=>{"room"=>6}}}}]
combine_em arr
#=> {"base"=>{"floor1"=>{"apt1"=>{"room"=>6}}}}
The last example of arr
(if it could occur), may not give the desired result. If so, it would be necessary to specify the desired return value in that case.
Hash#merge was changed in Ruby v2.6 to allow multiple arguments, which is why we can now write
arr = [{:a=>1}, {:b=>2}, {:c=>3}]
{}.merge(*arr)
#=> {:a=>1, :b=>2, :c=>3}
To support earlier versions of Ruby, write
arr.reduce(&:merge)
which is shorthand for
arr.reduce { |h,g| h.merge(g) }
See Enumerable#reduce (aka inject
).
To gain a full understand of how the recursion works it may be necessary to salt the method with puts
statements.