代码之家  ›  专栏  ›  技术社区  ›  simo

将两个哈希与共享根合并

  •  0
  • simo  · 技术社区  · 5 年前

    我有:

    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}}}} 
    
    4 回复  |  直到 5 年前
        1
  •  1
  •   Benissimo    5 年前

    如果您正在使用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

        2
  •  1
  •   iGian    5 年前

    手动处理:

    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
    

    deep_merge(apartment1, apartment2) #=> {"base"=>{"floor1"=>{"apartment1"=>{"rooms_number"=>4}, "apartment2"=>{"rooms_number"=>6}}}}
    
        3
  •  1
  •   Cary Swoveland    5 年前

    以下递归方法应提供所需的结果。

    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

        4
  •  0
  •   sawa    5 年前

    您不希望在根级别合并,而是希望在更深的两个级别合并。

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