我有:
apartment1 = {"base" => {"floor1" => {"apartment1" => {"rooms_number" => 4}}}}
apartment2 = {"base" => {"floor1" => {"apartment2" => {"rooms_number" => 6}}}}
共享{"base" => {"floor1" =>
的人。
我如何将共享部分下的公寓合并以获得:
{"base" => {"floor1" => {
"apartment1" => {"rooms_number" => 6},
"apartment2" => {"rooms_number" => 6}
}}}
我将apartment1
和apartment2
合并到apartments
中,得到了:
apartments = {}
apartments.merge!(apartment1)
# => {"base" => {"floor1" => {"apartment1" => {"rooms_number" => 4}}}}
apartments.merge!(apartment2)
# => {"base" => {"floor1" => {"apartment2" => {"rooms_number" => 6}}}}
答案 0 :(得分:1)
如果您使用的是Rails(或者在任何情况下,如果您愿意使用ActiveSupport),都可以通过deep_merge
执行此操作:
2.5.1 :001 > apartment1= {"base" => {"floor1" => {"apartment1" => {"rooms_number" => 4} } }}
=> {"base"=>{"floor1"=>{"apartment1"=>{"rooms_number"=>4}}}}
2.5.1 :002 > apartment2= {"base" => {"floor1" => {"apartment2" => {"rooms_number" => 6} } }}
=> {"base"=>{"floor1"=>{"apartment2"=>{"rooms_number"=>6}}}}
2.5.1 :003 > apartments = apartment1.deep_merge apartment2
=> {"base"=>{"floor1"=>{"apartment1"=>{"rooms_number"=>4}, "apartment2"=>{"rooms_number"=>6}}}}
请参见https://apidock.com/rails/Hash/deep_merge
另请参阅以下类似问题: Ruby: merge nested hash
答案 1 :(得分:1)
手动处理:
apartments = apartment1
apartments['base']['floor1'].merge!(apartment2['base']['floor1'])
p apartments
#=> {"base"=>{"floor1"=>{"apartment1"=>{"rooms_number"=>4}, "apartment2"=>{"rooms_number"=>6}}}}
或者从Rails窃取(!)深度合并算法:
def deep_merge(first, second)
first.merge(second) do |key, oldval, newval|
oldval = oldval.to_hash if oldval.respond_to?(:to_hash)
newval = newval.to_hash if newval.respond_to?(:to_hash)
oldval.class.to_s == 'Hash' && newval.class.to_s == 'Hash' ? deep_merge(oldval, newval) : newval
end
end
因此您可以在纯Ruby中使用它:
deep_merge(apartment1, apartment2) #=> {"base"=>{"floor1"=>{"apartment1"=>{"rooms_number"=>4}, "apartment2"=>{"rooms_number"=>6}}}}
答案 2 :(得分:1)
以下递归方法应该可以提供预期的结果。
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}}}}
arr
的最后一个示例(如果可能发生的话)可能无法提供所需的结果。如果是这样,在这种情况下,有必要指定所需的返回值。
Hash#merge在Ruby v2.6中进行了更改,以允许多个参数,这就是为什么我们现在可以编写
arr = [{:a=>1}, {:b=>2}, {:c=>3}]
{}.merge(*arr)
#=> {:a=>1, :b=>2, :c=>3}
要支持早期版本的Ruby,请写
arr.reduce(&:merge)
这是速记
arr.reduce { |h,g| h.merge(g) }
请参见Enumerable#reduce(又名inject
)。
要完全了解递归的工作方式,可能有必要用puts
语句对该方法加盐。
答案 3 :(得分:0)
您不希望在根级别进行合并,而希望在更深的两个级别进行合并。
apartment1.merge(apartment2){|_, h1, h2| h1.merge(h2){|_, h1, h2| h1.merge(h2)}}
# =>
# {"base" => {"floor1" => {
# "apartment1" => {"rooms_number" => 4},
# "apartment2" => {"rooms_number" => 6}
# }}}