2017-03-22 30 views
0

我已经找到了在JS中完成的问题的解决方案,但我需要在Ruby(RoR)中完成该工作。这里是链接问题和解决方案:Find average value for array of hashes using multiple group by用多个键组合散列数组以找到Ruby中的平均数

所以我有哈希值的阵列,需要通过按键(第一subject_id然后element_id),然后找到平均值为他们进行分组。数组中的散列数量不固定。

下面是输入数组:

a=[ 
{:subject_id=>1, :element_id=>2, :value=>55}, 
{:subject_id=>1, :element_id=>4, :value=>33}, 
{:subject_id=>1, :element_id=>2, :value=>33}, 
{:subject_id=>1, :element_id=>4, :value=>1}, 
{:subject_id=>1, :element_id=>2, :value=>7}, 
{:subject_id=>1, :element_id=>4, :value=>4}, 
{:subject_id=>2, :element_id=>2, :value=>3}, 
{:subject_id=>2, :element_id=>2, :value=>5}, 
{:subject_id=>2, :element_id=>4, :value=>9} 
] 

结果:

b=[ 
{:subject_id=>1, :element_id=>2, :value=>95}, 
{:subject_id=>1, :element_id=>4, :value=>38}, 
{:subject_id=>2, :element_id=>2, :value=>8}, 
{:subject_id=>2, :element_id=>4, :value=>9} 
] 

回答

0

在问题中显示的结果是不平均,它的总和,所以结果会有所不同:

def groupByAndAverage(a) 
    b = [] 

    a.each_with_index do |element, key| 
     index = b.index do |x| 
     x != element && 
      x[:subject_id] == element[:subject_id] && 
      x[:element_id] == element[:element_id] 
     end 
     if index 
     b[index][:value] += element[:value] 
     b[index][:amount] += 1 
     else 
     b.push a[key].merge(amount: 1) 
     end 

     true 
    end 
    b.map do |element| 
     element[:value] = element[:value]/element[:amount] 
     element.delete(:amount) 
     element 
    end 
    b 
    end 

而从这个结果是:

[{:subject_id=>1, :element_id=>2, :value=>31}, 
    {:subject_id=>1, :element_id=>4, :value=>12}, 
    {:subject_id=>2, :element_id=>2, :value=>4}, 
    {:subject_id=>2, :element_id=>4, :value=>9}] 
+0

是的,谢谢你指出,那是一个错误 – user7754069

0

我建议一个计数散列被用于获得所述的小计键:value然后构造所需阵列的来自该散列的散列。这使用Hash#new的形式,它接受一个参数,它是哈希的默认值。这意味着如果散列h没有密钥k,则h[k]将返回默认值。

计算总计

a.each_with_object(Hash.new(0)) {|g,h| h[[g[:subject_id], g[:element_id]]] += g[:value]}. 
    map {|(sub, el), tot| { subject_id: sub, element_id: el, value: tot}} 
    #=> [{:subject_id=>1, :element_id=>2, :value=>95}, 
    # {:subject_id=>1, :element_id=>4, :value=>38}, 
    # {:subject_id=>2, :element_id=>2, :value=>8}, 
    # {:subject_id=>2, :element_id=>4, :value=>9}] 

红宝石,作为第一步骤,解压表达

h[[g[:subject_id], g[:element_id]]] += g[:value] 

改变它

h[[g[:subject_id], g[:element_id]]] = h[[g[:subject_id], g[:element_id]]] + g[:value] 

如果h不具有关键[g[:subject_id], g[:element_id]]h[[g[:subject_id], g[:element_id]]]在等于的右侧返回默认值0

注意

a.each_with_object(Hash.new(0)) {|g,h| h[[g[:subject_id], g[:element_id]]] += g[:value]} 
    #=> {[1, 2]=>95, [1, 4]=>38, [2, 2]=>8, [2, 4]=>9} 

计算平均

只有一个小的变化,需要计算平均值。

a.each_with_object({}) do |g,h| 
    pair = [g[:element_id], g[:subject_id]] 
    h[pair] = {tot: 0, count: 0} unless h.key?(pair) 
    h[pair] = {tot: h[pair][:tot] + g[:value], count: h[pair][:count]+1} 
end.map {|(sub, el),h| {subject_id: sub, element_id: el, 
         average: (h[:tot].to_f/h[:count]).round(1)}} 
    #=> [{:subject_id=>2, :element_id=>1, :average=>31.7}, 
    # {:subject_id=>4, :element_id=>1, :average=>12.7}, 
    # {:subject_id=>2, :element_id=>2, :average=>4.0}, 
    # {:subject_id=>4, :element_id=>2, :average=>9.0}] 

a.each_with_object({}) do |g,h| 
    pair = [g[:element_id], g[:subject_id]] 
    h[pair] = {tot: 0, count: 0} unless h.key?(pair) 
    h[pair] = {tot: h[pair][:tot] + g[:value], count: h[pair][:count]+1} 
end 
    #=> {[2, 1]=>{:tot=>95, :count=>3}, [4, 1]=>{:tot=>38, :count=>3}, 
    # [2, 2]=>{:tot=> 8, :count=>2}, [4, 2]=>{:tot=> 9, :count=>1}} 
+0

谢谢你的帮助,我犯了一个错误充足的地方,我显示结果,而不是平均水平。 – user7754069

+0

我添加了平均值的计算。 –