计算哈希数组中多个值的最简洁方法?

时间:2015-01-09 18:47:25

标签: ruby hash count

我有一系列像这样的哈希:

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.injectdata.count

4 个答案:

答案 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}}