【问题标题】:Ruby: Nested hash loses keys and values on merging with another nested hashRuby:嵌套散列在与另一个嵌套散列合并时丢失键和值
【发布时间】:2020-05-08 15:40:08
【问题描述】:

我有一个哈希-

h1 = {"a"=>{"x"=>"1","y"=>"2"}, "b"=>"z"}

我还有另一个哈希 h2,它基本上更新了 h1 中某些键的值

h2 = {"a"=>{"x"=>"3"}, "b"=>"q"}

当我做一个 -

h1.merge(h2)

我期待它回来-

{"a"=>{"x"=>"3","y"=>"2"}, "b"=>"q"}

但它实际上给了我- {"a"=>{"x"=>"3"}, "b"=>"q"}

我需要做什么才能获得{"a"=>{"x"=>"3","y"=>"2"}, "b"=>"q"}

使用 Rails。红宝石版本是2.6.0

【问题讨论】:

  • 如果键在两者中都存在,则合并哈希的键值在所有情况下都会替换第一个。如果你有h1 = {"a" => "x", "b" => {"a" => "4", "b" => "5"}h2 = {"a" => {"f" => "1", "g" => "2"}, "b" => "y"},你希望它做什么?
  • 如果你不能使用 Rails 的 deep_merge,那么也许你想自己实现它。这里有一个非常优雅的 Ruby 解决方案:stackoverflow.com/a/32268934/1505529。但是,正如@lurker 所指出的,在您的情况下,值并不总是散列,您必须添加一些逻辑

标签: ruby hash


【解决方案1】:

Hash#merge 的工作方式是一致的:如果键在两者中都存在,则合并哈希的键值在所有情况下都会替换第一个。您需要递归合并。

有一个deep_merge available in Rails。但是,如果您没有使用 Rails,或者它不符合您的要求,您可以相当轻松地自行开发。

Hash#merge 确实支持一个可以提供帮助的块:

h1.merge(h2) { |k, old, new| (old.instance_of?(Hash) && new.instance_of?(Hash)) ?
                             old.merge(new) : new }

如果您只有一层深度的嵌入式哈希,这将起作用。如果你有任意深度的嵌套哈希,你可以用 deep_merge 修补 Hash

class Hash
  def deep_merge(h)
    self.merge(h) { |k, old, new| (old.instance_of?(Hash) && new.instance_of?(Hash)) ?
                            old.deep_merge(new) : new }
  end
end

或类似的东西... :) 如果在这两种情况下都存在哈希,这将递归合并,否则,它会像往常一样替换。您可以根据自己的喜好进行修改。

为您的案例尝试一下:

2.6.1 :008 > class Hash
2.6.1 :009?>   def deep_merge(h)
2.6.1 :010?>     self.merge(h) { |k, old, new| (old.instance_of?(Hash) && new.instance_of?(Hash)) ?
2.6.1 :011 >                                   old.deep_merge(new) : new }
2.6.1 :012?>   end
2.6.1 :013?> end
 => :deep_merge
2.6.1 :014 > h1 = {"a"=>{"x"=>"1","y"=>"2"}, "b"=>"z"}
 => {"a"=>{"x"=>"1", "y"=>"2"}, "b"=>"z"}
2.6.1 :015 > h2 = {"a"=>{"x"=>"3"}, "b"=>"q"}
 => {"a"=>{"x"=>"3"}, "b"=>"q"}
2.6.1 :016 > h1.deep_merge(h2)
 => {"a"=>{"x"=>"3", "y"=>"2"}, "b"=>"q"}
2.6.1 :017 >

【讨论】:

  • 你应该使用'&&'而不是'and'
  • @Olkin 是的,明白了,谢谢。 &&(相对于and)的优先级更高,我需要添加一些括号......
  • 不,你不需要,关键字and 需要括号,因为? : 的优先级高于and,所以只有最后一个表达式会被评估为and&& 的优先级高于 ? :,因此不需要括号。经验法则是使用and 进行流控制,使用&& 进行布尔逻辑。
  • @lurker 啊,我以为你是指(old.instance_of?(Hash) && new.instance_of?(Hash)) 周围的括号,可以省略。
  • 是吗?无论是否需要,我都有一个习惯,总是使用它们来清楚地说明它们。 :)
猜你喜欢
  • 2014-09-13
  • 2013-07-08
  • 2021-11-03
  • 2013-03-14
  • 2017-10-02
  • 2018-11-07
  • 2013-01-30
  • 2014-06-24
  • 2014-07-28
相关资源
最近更新 更多