基本上我有一系列像这样的哈希:
[
{ :id => 20, :total => 1, :total2 => 0 },
{ :id => 21, :total => 1, :total2 => 0 },
{ :id => 22, :total => 2, :total2 => 0 },
{ :id => 23, :total => 1, :total2 => 0 },
{ :id => 20, :total => 1, :total2 => 0 },
{ :id => 21, :total => 1, :total2 => 0 },
{ :id => 22, :total => 1, :total2 => 1 },
{ :id => 23, :total => 1, :total2 => 0 }
]
我希望数组将最后两个哈希列相加,保留第一个(:id
)作为标识符:
[
{ :id => 20, :total => 2, :total2 => 0 },
{ :id => 21, :total => 2, :total2 => 0 },
{ :id => 22, :total => 3, :total2 => 1 }
]
我环顾四周,似乎在这个实例中使用了.inject()
方法,但我无法弄清楚语法/如何使用它。
我要找的是将第一列(:id
)保留为ID字段;如果有另一个具有此ID的哈希值,就像我上面的例子中那样,两个哈希值应该加在一起。
答案 0 :(得分:1)
你能试试吗?
array = [{:stemp=>20, :vtotal=>1, :avg=>0}, {:stemp=>21, :vtotal=>1, :avg=>0},{:stemp=>22, :vtotal=>2, :avg=>0}, {:stemp=>23, :vtotal=>1, :avg=>0}, {:stemp=>20, :vtotal=>1, :avg=>0}, {:stemp=>21, :vtotal=>1, :avg=>0}, {:stemp=>22, :vtotal=>1, :avg=>1}, {:stemp=>23, :vtotal=>1, :avg=>0}]
result = array.group_by{|h| h[:stemp]}.map do |stemp, hashes|
{ stemp: stemp, vtotal: hashes.map{|h| h[:vtotal]}.inject(:+), avg: hashes.map{|h| h[:avg]}.inject(:+) }
end
使用ruby 1.9.3将其复制粘贴到IRB控制台中,输出:
[
{:stemp=>20, :vtotal=>2, :avg=>0},
{:stemp=>21, :vtotal=>2, :avg=>0},
{:stemp=>22, :vtotal=>3, :avg=>1},
{:stemp=>23, :vtotal=>2, :avg=>0}
]
答案 1 :(得分:0)
我重新格式化了问题和答案中的数据,以便其他人更容易看到正在发生的事情。
data = [
{ :stemp => 20, :vtotal => 1, :avg => 0 },
{ :stemp => 21, :vtotal => 1, :avg => 0 },
{ :stemp => 22, :vtotal => 2, :avg => 0 },
{ :stemp => 23, :vtotal => 1, :avg => 0 },
{ :stemp => 20, :vtotal => 1, :avg => 0 },
{ :stemp => 21, :vtotal => 1, :avg => 0 },
{ :stemp => 22, :vtotal => 1, :avg => 1 },
{ :stemp => 23, :vtotal => 1, :avg => 0 }
]
首先,按stemp
。
data = data.group_by { |datum| datum[:stemp] }
然后迭代每个stemp
及其条目。
data = data.map do |stemp, entries|
# this pulls out each hash's :vtotal entry and then combines it with the + operator
vtotal = entries.map { |entry| entry[:vtotal] }.inject(&:+)
# this does the same as above, but for the avg entry
avg = entries.map { |entry| entry[:avg] }.inject(&:+)
{ :stemp => stemp, :vtotal => vtotal, :avg => avg }
end
此输出
[
{ :stemp => 20, :vtotal => 2, :avg => 0 },
{ :stemp => 21, :vtotal => 2, :avg => 0 },
{ :stemp => 22, :vtotal => 3, :avg => 1 },
{ :stemp => 23, :vtotal => 2, :avg => 0 }
]
答案 2 :(得分:0)
此解决方案存在可读性,但我想提供它以供参考。
Hash#merge接受在找到碰撞密钥时将执行的块。
arr = [ {:id => 20, :total => 1, :total2 => 0} ... ]
arr.group_by{ |h| h[:id] }.map do |_, hash|
hash.reduce do |hash_a, hash_b|
hash_a.merge(hash_b){ |key, old, new| key == :id ? old : old + new }
end
end
答案 3 :(得分:0)
这个也有效
arr.group_by{|t| t[:stemp]}.map {|key, value| value.inject({}) { |hash, values| values.merge(hash){ |key, v1, v2| key == :stemp ? v1 : v1+v2 }}}
更改为:id
arr.group_by{|t| t[:id]}.map {|key, value| value.inject({}) { |hash, values| values.merge(hash){ |key, v1, v2| key == :id ? v1 : v1+v2 }}}
答案 4 :(得分:0)
[{"4"=>"20.0"}, {"4"=>"20.0"}, {"4"=>"10.0"}, {"4"=>"10.0", "5"=>"10.0"}, {"4"=>"10.0", "5"=>"0.0"}, {"4"=>"10.0"}, {"4"=>"10.0"}, {"4"=>"0.0", "5"=>"10.66"}, {"4"=>"20.0"}, {"4"=>"10.0"}, {"4"=>"10.0"}, {"4"=>"0.0"}].map{|m| m.map{|k,v| v.to_f}.sum()}.sum()