【发布时间】:2009-12-30 15:37:20
【问题描述】:
有没有一种简单或优雅的方法来合并两个哈希而不覆盖重复键?
也就是说,如果密钥存在于原始哈希中,我不想更改它的值。
【问题讨论】:
-
你真的是指数组(例如:['a', 'b', 'c'])还是哈希(例如:{'a' => 1, 'b' => 2, 'c' => 3})?
-
抱歉,我说的是哈希 :)
标签: ruby
有没有一种简单或优雅的方法来合并两个哈希而不覆盖重复键?
也就是说,如果密钥存在于原始哈希中,我不想更改它的值。
【问题讨论】:
标签: ruby
如果您有两个哈希值,options 和 defaults,并且您想在不覆盖现有键的情况下将 defaults 合并到 options,您真正想要做的是相反的操作:将 options 合并到 @ 987654327@:
options = defaults.merge(options)
或者,如果您使用的是 Rails,您可以这样做:
options.reverse_merge!(defaults)
【讨论】:
reverse_merge!
标准 Ruby 库中有一种方法可以合并散列而不覆盖现有值或重新分配散列。
important_hash.merge!(defaults) { |key, important, default| important }
【讨论】:
如果您的问题是原始哈希值和第二个哈希值都可能具有重复的键,并且您不想在任一方向上覆盖,您可能需要进行简单的手动合并,并进行某种冲突检查和处理:
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 中的。另外,我已经有几个月没有做任何 ruby 了,所以这可能在语法上不正确,但你应该能够理解要点。
或者将键的值重新定义为一个数组,以便 hash1[key] 返回 hash1 的原始值和 hash2 的值。取决于你希望你的结果是什么。
【讨论】:
在这里您可以通过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 }
【讨论】:
如果您想合并两个哈希 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? })
【讨论】: