有没有一种简单的或 优雅的方法来合并两个哈希而不覆盖重复的关键字?
也就是说,如果键出现在原始散列中,我不想改变它的值。
如果你有两个散列,options和 defaults,你想合并 defaults到 options而不覆盖现有的关键字,你真正想做的是相反的: 合并 options到 defaults:
options
defaults
options = defaults.merge(options)
或者,如果你正在使用 Rails,你可以这样做:
options.reverse_merge!(defaults)
如果你的问题是,原始散列和第二个散列都可能有重复的键,你不想覆盖任何一个方向,你可能不得不去一个简单的手动合并,某种冲突检查和处理:
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-Origin-whatever”的键——你最好在键上加上一个数字,这样它就变成了 key1、 key2等等,直到你找到一个还没有在 hash1中的键。另外,我已经几个月没有使用过 Ruby 了,所以语法上可能不太正确,但是你应该能够理解它的要点。
或者将键的值重新定义为数组,这样 hash1[ key ]返回 hash1的原始值和 hash2的值。取决于你真正想要的结果是什么。
在标准 Ruby 库中有一种方法可以合并散列,而不会覆盖现有的值或重新分配散列。
important_hash.merge!(defaults) { |key, important, default| important }
这里你可以通过 reverse_merge合并你的2个散列
reverse_merge
order = { id: 33987, platform: 'web' } user = { name: 'Jhon Doe', email: 'jhon.doe@gmail.com' } newHash = order.reverse_merge!(user) render json: { data: newHash, status: 200 } # => {:name=>"Jhon Doe", :email=>"jhon.doe@gmail.com", :id=>33987, :platform=>"web"}
如果希望在不覆盖目标散列的情况下合并两个散列 options和 defaults,可以使用 select检查目标散列中是否已经存在密钥。这是一个没有 Rails 的纯 Ruby 解决方案:
select
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,并且您希望覆盖它:
nil
options.merge!(defaults.select{ |k,_| options[k].nil? })