使用新函数扩展ruby类(哈希)(recursive_merge)

时间:2016-08-01 12:06:54

标签: ruby

如果我想以递归方式合并2个哈希值,我可以使用以下函数执行此操作:

=TEXT(DATE(MID(A1,1,4),MID(A1,5,2),MID(A1,7,2))+TIME(MID(A1,9,2),MID(A1,11,2),MID(A1,13,2)),"dd/mm/yyyy hh:mm")

这很有效,我现在可以做到:

def recursive_merge(a,b)
  a.merge(b) {|key,a_item,b_item| recursive_merge(a_item,b_item) }
end

但我想将此添加为类似于aHash = recursive_merge(aHash,newHash) 的自我更新样式方法。我可以添加返回函数:

merge!

但我不确定如何重新创建class Hash def recursive_merge(newHash) self.merge { |key,a_item,b_item| a_item.recursive_merge(b_item) } end end 函数,在没有关联的情况下更新原始对象。

bang
根据评论

编辑示例。

class Hash
  def recursive_merge!(newHash)
    self.merge { |key,a_item,b_item| a_item.recursive_merge(b_item) }
    # How do I set "self" to this new hash?
  end
end

定期合并会导致h={:a=>{:b => "1"} h.recursive_merge!({:a=>{:c=>"2"}) => {:a=>{:b=>"1", :c="2"}}

覆盖:b=>"1"

1 个答案:

答案 0 :(得分:1)

使用merge!而不是尝试更新self。我认为使用合并是不合理的!除了最高级别之外的任何地方,所以我不会递归地称之为爆炸版本。相反,使用合并!在顶层,并递归调用非爆炸方法。

检查合并的两个值确实是哈希值也是明智的,否则如果尝试对非哈希对象进行recursive_merge,则可能会出现异常。

#!/usr/bin/env ruby

class Hash
  def recursive_merge(other)
    self.merge(other) { |key, value1, value2| value1.is_a?(Hash) && value2.is_a?(Hash) ? value1.recursive_merge(value2) : value2}
  end

  def recursive_merge!(other)
    self.merge!(other) { |key, value1, value2| value1.is_a?(Hash) && value2.is_a?(Hash) ? value1.recursive_merge(value2) : value2}
  end
end


h1 = { a: { b:1, c:2 }, d:1 }
h2 = { a: { b:2, d:4 }, d:2 }
h3 = { d: { b:1, c:2 } }


p h1.recursive_merge(h2) # => {:a=>{:b=>2, :c=>2, :d=>4}, :d=>2}
p h1.recursive_merge(h3) #  => {:a=>{:b=>1, :c=>2}, :d=>{:b=>1, :c=>2}}

p h1.recursive_merge!(h2) # => {:a=>{:b=>2, :c=>2, :d=>4}, :d=>2}
p h1 # => {:a=>{:b=>2, :c=>2, :d=>4}, :d=>2}

如果你有一个特定的理由完全合并到位,可能是为了速度,你可以尝试递归地进行第二个函数调用,而不是将递归委托给第一个函数。请注意,如果散列存储共享对象,可能会产生意外的副作用。

示例:

h1 = { a:1, b:2 }
h2 = { a:5, c:9 }
h3 = { a:h1, b:h2 }
h4 = { a:h2, c:h1 }

p h3.recursive_merge!(h4)
# Making recursive calls to recursive_merge
# => {:a=>{:a=>5, :b=>2, :c=>9}, :b=>{:a=>5, :c=>9}, :c=>{:a=>1, :b=>2}}
# Making recursive calls to recursive_merge!
# => {:a=>{:a=>5, :b=>2, :c=>9}, :b=>{:a=>5, :c=>9}, :c=>{:a=>5, :b=>2, :c=>9}}

如您所见,存储在key:c下的h1的第二个(共享)副本被更新以反映键下的h1和h2的合并:a。这可能是令人惊讶和不必要的。因此,为什么我建议使用recursive_merge进行递归,而不是recursive_merge!