使用相同的键合并Ruby嵌套哈希
我在Ruby中有几个散列,它们内部有嵌套的散列,结构非常相似。它们看起来像这样:使用相同的键合并Ruby嵌套哈希,ruby,hash-of-hashes,Ruby,Hash Of Hashes,我在Ruby中有几个散列,它们内部有嵌套的散列,结构非常相似。它们看起来像这样: a = { "year_1": { "sub_type_a": { "label1": value1 } }, "year_2": { "sub_type_a": { "label2": value2 } } } b = { "year_1": {
a = {
"year_1": {
"sub_type_a": {
"label1": value1
}
},
"year_2": {
"sub_type_a": {
"label2": value2
}
}
}
b = {
"year_1": {
"sub_type_a": {
"label3": value3
}
},
"year_2": {
"sub_type_a": {
"label4": value4
}
}
}
c = {
"year_1": {
"sub_type_a": {
"label5": value5
}
},
"year_2": {
"sub_type_a": {
"label6": value6
}
}
}
result = {
"year_1": {
"sub_type_a": {
"label1": value1,
"label3": value3,
"label5": value5
}
},
"year_2": {
"sub_type_a": {
"label2": value2,
"label4": value4,
"label6": value6
}
}
}
我想将它们合并到一个散列中,这样就可以在不覆盖其他值的情况下尽可能地合并嵌套数据:
a = {
"year_1": {
"sub_type_a": {
"label1": value1
}
},
"year_2": {
"sub_type_a": {
"label2": value2
}
}
}
b = {
"year_1": {
"sub_type_a": {
"label3": value3
}
},
"year_2": {
"sub_type_a": {
"label4": value4
}
}
}
c = {
"year_1": {
"sub_type_a": {
"label5": value5
}
},
"year_2": {
"sub_type_a": {
"label6": value6
}
}
}
result = {
"year_1": {
"sub_type_a": {
"label1": value1,
"label3": value3,
"label5": value5
}
},
"year_2": {
"sub_type_a": {
"label2": value2,
"label4": value4,
"label6": value6
}
}
}
也可以有几个子类型,而不是只有一个,但这是一般的想法
如果我使用merge
函数,它只会覆盖sub_类型散列中的标签值数据,只剩下一条记录
有没有一个简单的方法来实现这一点?我可以编写一个递归迭代散列的函数,并找出内部要添加的内容,但感觉应该有一种更简单的方法。Hash#merge
采用可选的冲突解决块,只要主题和参数中都有密钥,就会调用该块
您可以使用它来递归地合并哈希。我们得到以下信息
a = {:year_1=>{:sub_type_a=>{:label1=>"value1"}},
:year_2=>{:sub_type_a=>{:label2=>"value2"}}}
b = {:year_1=>{:sub_type_a=>{:label3=>"value3"}},
:year_2=>{:sub_type_a=>{:label4=>"value4"}}}
c = {:year_1=>{:sub_type_a=>{:label5=>"value5"}},
:year_2=>{:sub_type_a=>{:label6=>"value6"}}}
arr = [a, b, c]
我们可以如下构造所需的散列
arr.each_with_object({}) do |g,h|
g.each do |yr,v|
k,f = v.first
h.update(yr=>{ k=>f }) { |_,o,n| { k=>o[k].merge(n[k]) } }
end
end
#=> {:year_1=>{:sub_type_a=>{:label1=>"value1", :label3=>"value3",
# :label5=>"value5"}},
# :year_2=>{:sub_type_a=>{:label2=>"value2", :label4=>"value4",
# :label6=>"value6"}}}
它使用(也称为merge!
)的形式,使用块来确定合并的两个哈希中存在的键的值。有关该块的三个块变量的说明,请参见链接。我使用下划线(一个有效的局部变量)作为第一个块变量,即公共键,以向读者发出在块计算中不使用它的信号。这是一个普遍的惯例
对于任何对计算的血淋淋的细节感兴趣的人(理解发生了什么的一种可靠方法),我将执行添加了一些put
语句的代码
arr.each_with_object({}) do |g,h|
puts "g=#{g}"
puts "h=#{h}"
g.each do |yr,v|
puts " yr=#{yr}"
puts " v=#{v}"
k,f = v.first
puts " k=#{k}"
puts " f=#{f}"
puts " yr=>{ k=>f } = #{yr}=>#{v} = #{{ yr=>v }}"
h.update(yr=>{ k=>f }) do |_,o,n|
puts " _=#{_}"
puts " o=#{o}"
puts " n=#{n}"
puts " { k=>o[k].merge(n[k]) }"
puts " => { #{k}=>#{o[k]}.merge(#{n[k]}) }"
{ k=>o[k].merge(n[k]) }.tap { |e| puts " => #{e}" }
end
end
end
将显示以下内容
g={:year_1=>{:sub_type_a=>{:label1=>"value1"}},
:year_2=>{:sub_type_a=>{:label2=>"value2"}}}
h={}
yr=year_1
v={:sub_type_a=>{:label1=>"value1"}}
k=sub_type_a
f={:label1=>"value1"}
yr=>{ k=>f } = year_1=>{:sub_type_a=>{:label1=>"value1"}} =
{:year_1=>{:sub_type_a=>{:label1=>"value1"}}}
yr=year_2
v={:sub_type_a=>{:label2=>"value2"}}
k=sub_type_a
f={:label2=>"value2"}
yr=>{ k=>f } = year_2=>{:sub_type_a=>{:label2=>"value2"}} =
{:year_2=>{:sub_type_a=>{:label2=>"value2"}}}
类似的东西
将每个\u与\u对象
、每个
和合并
组合,这样您就可以通过每个散列进行迭代,并在合并值存在时将其分配给临时新值:
[a, b, c].each_with_object({}) do |years_data, hash|
years_data.each do |year, data|
hash[year] = (hash[year] || {}).merge(data) { |_, oldval, newval| oldval.merge(newval) }
end
end
# {
# :year_1 => {
# :sub_type_a => {
# :label1 => :value1,
# :label3 => :value3,
# :label5 => :value5
# }
# },
# :year_2 => {
# :sub_type_a => {
# :label2 => :value2,
# :label4 => :value4,
# :label6 => :value6
# }
# }
# }
如果您使用的是Rails(或ActiveSupport),您可能想看看它,它为您处理嵌套哈希的合并这应该是一条注释。这应该是一条注释。这没有任何意义。这是对问题的回答,而不是评论。