如何在Ruby中合并两个哈希而不覆盖重复的键?


Answers:


232

如果你有两个散列,optionsdefaults和要合并defaultsoptions而不覆盖现有的密钥,你真正想要做的是相反的:合并optionsdefaults

options = defaults.merge(options)

或者,如果您使用的是Rails,则可以执行以下操作:

options.reverse_merge!(defaults)

完全同意,非常感谢reverse_merge!方法不知道:)
克劳迪奥·阿西亚雷西

为什么在这里需要括号?您不能只执行default.merge选项。
Donato

1
reverse_merge!由于轨道5.1中的安全性问题,他们将弃用
Mirv-Matt Matt

@ Mirv-Matt-我看不到折旧通知。apidock.com/rails/v6.0.0/Hash/reverse_merge%21
Kshitij

17

标准Ruby库中有一种方法可以合并哈希,而无需覆盖现有值或重新分配哈希。

important_hash.merge!(defaults) { |key, important, default| important }

3

如果您的问题是原始哈希和第二个哈希可能都具有重复的键,并且您不想在任一方向上覆盖,则可能必须进行简单的手动合并,并进行某种冲突检查和处理:

hash2.each_key do |key|
  if ( hash1.has_key?(key) )
       hash1[ "hash2-originated-#{key}" ] = hash2[key]
  else
       hash1[key]=hash2[key]
  end
end

显然,这是非常基本的,并假设hash1没有任何称为“ hash2-originated-whatever”的键-最好在该键上添加一个数字,使其成为key1,key2等,直到您按下为止尚未包含在hash1中的一个。另外,几个月来我都没有做过任何红宝石,因此在语法上可能不正确,但是您应该能够掌握要点。

或者,将键的值重新定义为数组,以便hash1 [key]从hash1返回原始值,从hash2返回该值。取决于您希望结果是什么。


如果不同时保留两个密钥,而是将同一密钥的值相加怎么办?
Tom KC Chiu 2015年

1
@ TomK.C.Chiu在很大程度上取决于我们无法从问题中判断的情况-如果hash1中的值是字符串而hash2是整数,那该怎么办?在某些情况下,这可能是一个可行的选择,但更常见的是会引起问题-使用列表值的建议在此情况下非常干净。
glenatron 2015年

0

在这里您可以合并您的2个哈希 reverse_merge

order = {
 id: 33987,
 platform: 'web'
}

user = {
  name: 'Jhon Doe',
  email: 'jhon.doe@gmail.com' 
}
newHash = oder.reverse_merge!(user)
render json: { data: newHash, status: 200 }

0

如果要合并两个哈希options并且defaults不覆盖目标哈希,则可以检查select密钥是否已存在于目标哈希中。这是不带Rails的纯Ruby解决方案:

options  = { "a" => 100, "b" => 200 }
defaults = { "b" => 254, "c" => 300 }
options.merge!(defaults.select{ |k,_| not options.has_key? k })

# output
# => {"a"=>100, "b"=>200, "c"=>300}

或者,如果该密钥存在但包含但nil您想覆盖它:

options.merge!(defaults.select{ |k,_| options[k].nil? })
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.