我有一系列像这样的哈希:
data = [
{group: "A", result: 1},
{group: "B", result: 1},
{group: "A", result: 0},
{group: "A", result: 1},
{group: "B", result: 1},
{group: "B", result: 1},
{group: "B", result: 0},
{group: "B", result: 0}
]
该组只有A或B,结果只有1或0.我想计算每组的结果为0或1的次数,即得到这样的计数: / p>
A: result is "1" 2 times
result is "0" 1 time
B: result is "1" 3 times
result is "0" 2 times
我正在考虑将实际结果存储在嵌套哈希中,例如:
{ a: { pass: 2, fail: 1 }, b: { pass: 3, fail: 2 } }
但这可能不是最好的方式,所以我对这里的其他想法持开放态度。
在Ruby中执行此操作的最简洁方法是什么,只迭代数据一次?以某种方式使用data.inject
或data.count
?
答案 0 :(得分:3)
stats = Hash[data.group_by{|h| [h[:group], h[:result]] }.map{|k,v| [k, v.count] }]
#=> {["A", 1]=>2, ["B", 1]=>3, ["A", 0]=>1, ["B", 0]=>2}
我会将转换保留到您想要的格式; - )
答案 1 :(得分:0)
这种方式只会重复一次哈希:
result = Hash.new { |h, k| h[k] = { pass: 0, fail: 0 }}
data.each do |item|
result[item[:group]][item[:result] == 0 ? :fail : :pass] += 1
end
result
# => {"A"=>{:pass=>2, :fail=>1}, "B"=>{:pass=>3, :fail=>2}}
答案 2 :(得分:0)
如果这确实是你想要的输出,那么这样的事情就可以了:
def pass_fail_hash(a=[],statuses=[:pass,:fail])
a.map(&:dup).group_by{|h| h.shift.pop.downcase.to_sym}.each_with_object({}) do |(k,v),obj|
obj[k] = Hash[statuses.zip(v.group_by{|v| v[:result]}.map{|k,v| v.count})]
statuses.each {|status| obj[k][status] ||= 0 }
end
end
然后
pass_fail_hash data
#=> {:a=>{:pass=>2, :fail=>1}, :b=>{:pass=>3, :fail=>2}}
感谢@CarySwoveland指出我的原始方法未考虑没有传递或失败值的情况。现在已经解决了这个问题,以便像[{ group: "A", result: 1 }]
这样的哈希数组现在显示{a:{:pass => 1, :fail => 0}}
之前的{a:{:pass => 1, :fail => nil}}
。
答案 3 :(得分:0)
您可以使用Hash#update(与Hash#merge!
相同)的形式,它使用一个块来确定合并的两个哈希中包含的键的值:
data.map(&:values).each_with_object({}) { |(g,r),h|
h.update({g.to_sym=>{pass: r, fail: 1-r } }) { |_,oh,nh|
{ pass: oh[:pass]+nh[:pass], fail: oh[:fail]+nh[:fail] } } }
#=> {:A=>{:pass=>2, :fail=>1}, :B=>{:pass=>3, :fail=>2}}