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

时间:2009-12-30 15:37:20

标签: ruby

是否有一种简单或优雅的方式来合并两个哈希而不会覆盖重复的键?

也就是说,如果密钥存在于原始哈希中,我不想更改其值。

5 个答案:

答案 0 :(得分:211)

如果您有两个哈希optionsdefaults,并且您希望将defaults合并到options而不覆盖现有密钥,那么您真正想要做的就是反向:将options合并到defaults

options = defaults.merge(options)

或者,如果你正在使用Rails,你可以这样做:

options.reverse_merge!(defaults)

答案 1 :(得分:16)

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

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

答案 2 :(得分:4)

如果您的问题是原始哈希和第二个哈希都可能有重复的密钥并且您不想在任何一个方向上覆盖,那么您可能需要进行简单的手动合并以进行某种冲突检查和处理:

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的值。取决于你想要的结果是什么。

答案 3 :(得分:0)

在这里您可以通过reverse_merge

合并2个哈希
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 }

答案 4 :(得分:0)

如果要合并两个哈希optionsdefaults而不覆盖目标哈希,则可以用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? })