合并两个哈希有共享根

问题描述 投票:0回答:4

我有:

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}
}}}

我合并apartment1apartment2apartments,并得到了这一点:

apartments = {}
apartments.merge!(apartment1)
# => {"base" => {"floor1" => {"apartment1" => {"rooms_number" => 4}}}} 
apartments.merge!(apartment2)
# => {"base" => {"floor1" => {"apartment2" => {"rooms_number" => 6}}}} 
ruby hash
4个回答
0
投票

你想在根级别不合并,但在两个层次更深。

apartment1.merge(apartment2){|_, h1, h2| h1.merge(h2){|_, h1, h2| h1.merge(h2)}}
# =>
# {"base" => {"floor1" => {
#   "apartment1" => {"rooms_number" => 4},
#   "apartment2" => {"rooms_number" => 6}
# }}}

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
投票

手动处理:

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}}}}

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语句的方法。

© www.soinside.com 2019 - 2024. All rights reserved.