这是另一种方法。对于目前的问题,它可能不是首选,但它说明了一种有时有用的通用技术。
第一步:提取内键和外键:
okeys, ikeys = hash1.keys, hash1.values.first.keys
#=> [[:total, :defensive], [:gold, :dark]]
第 2 步:提取数值并计算差异
a = [hash1,hash2].
map { |h| h.values.map { |g| g.values_at(*ikeys) } }.
transpose.
map(&:transpose).
map { |a| a.reduce(:-) }
#=> [[100, 20], [100, 20]]
第 3 步:构造输出哈希
okeys.zip(a.map { |b| ikeys.zip(b).to_h }).to_h
#=> {:total=>{:gold=>100, :dark=>20}, :defensive=>{:gold=>100, :dark=>20}}
可以通过在第 3 步中替换 a 来组合第 2 步和第 3 步。ikeys 和 okeys 也可以替换为单行,但我不提倡这样做。
第 2 步说明
第 2 步可能看起来有点复杂,但如果您一次完成一个操作,实际上并非如此:
删除数值,使用Hash#values_at 以确保正确排序:
b = [hash1,hash2].map { |h| h.values.map { |g| g.values_at(*ikeys) } }
#=> [[[100, 500], [100, 500]], [[20, 200], [20, 200]]]
操作数组,直到它以适合计算差异的形式出现:
c = b.transpose
#=> [[[100, 500], [20, 200]], [[100, 500], [20, 200]]]
d = c.map(&:transpose)
#=> [[[100, 20], [500, 200]], [[100, 20], [500, 200]]]
计算差异:
a = d.map { |a| a.reduce(:-) }
#=> [[100, 20], [100, 20]]