这是另一种方法。对于目前的问题,这可能不是优选的,但它说明了一种有时有用的通用技术。
步骤1:提取内部和外部键:
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]]
尝试http://stackoverflow.com/questions/11958374/subtract-values-in-hash-from-corresponding-values-in-another-hash – Sach 2015-03-13 10:42:32