简体   繁体   English

如何从具有相同键的嵌套散列和数组中分组和添加值?

[英]How do I group and add values from nested hashes and arrays with same key?

I am trying to get the sum of points and average grade for each student inside this combination of hashes and arrays but all my attempts only return the general sum for all entries.我试图在这种散列和数组的组合中获得每个学生的总分和平均成绩,但我所有的尝试只返回所有条目的总和。 Any ideas?有任何想法吗?

student_data = 
  {"ST4"=>[{:student_id=>"ST4", :points=> 5, :grade=>5}, 
           {:student_id=>"ST4", :points=>10, :grade=>4}, 
           {:student_id=>"ST4", :points=>20, :grade=>5}], 
   "ST1"=>[{:student_id=>"ST1", :points=>10, :grade=>3}, 
           {:student_id=>"ST1", :points=>30, :grade=>4}, 
           {:student_id=>"ST1", :points=>45, :grade=>2}], 
   "ST2"=>[{:student_id=>"ST2", :points=>25, :grade=>5}, 
           {:student_id=>"ST2", :points=>15, :grade=>1}, 
           {:student_id=>"ST2", :points=>35, :grade=>3}], 
   "ST3"=>[{:student_id=>"ST3", :points=> 5, :grade=>5}, 
           {:student_id=>"ST3", :points=>50, :grade=>2}]}

The desired hash can be obtained thusly.可以这样获得所需的散列。

student_data.transform_values do |arr|
  points, grades = arr.map { |h| h.values_at(:points, :grade) }.transpose
  { :points=>points.sum, :grades=>grades.sum.fdiv(grades.size) }
end
  #=> {"ST4"=>{:points=>35, :grades=>4.666666666666667},
  #    "ST1"=>{:points=>85, :grades=>3.0},
  #    "ST2"=>{:points=>75, :grades=>3.0},
  #    "ST3"=>{:points=>55, :grades=>3.5}} 

The first value passed to the block is the value of the first key, 'ST4' and the block variable arr is assigned that value:传递给块的第一个值是第一个键的值'ST4'并且块变量arr被分配了该值:

a = student_data.first
  #=> ["ST4",
  #    [{:student_id=>"ST4", :points=> 5, :grade=>5},
  #     {:student_id=>"ST4", :points=>10, :grade=>4},
  #     {:student_id=>"ST4", :points=>20, :grade=>5}]
  #   ] 
arr = a.last
  #=> [{:student_id=>"ST4", :points=> 5, :grade=>5},
  #    {:student_id=>"ST4", :points=>10, :grade=>4},
  #    {:student_id=>"ST4", :points=>20, :grade=>5}]

The block calculations are as follows.块计算如下。 The first value of arr passed by map to the inner block is map传递给内部块的arr的第一个值是

h = arr.first
  #=> {:student_id=>"ST4", :points=>5, :grade=>5} 
h.values_at(:points, :grade)
  #=> [5, 5] 

After the remaining two elements of arr are passed to the block we have在将arr的其余两个元素传递给块后,我们有

b = arr.map { |h| h.values_at(:points, :grade) }
  #=> [[5, 5], [10, 4], [20, 5]] 

Then然后

points, grades = b.transpose
  #=> [[5, 10, 20], [5, 4, 5]] 
points
  #=> [5, 10, 20] 
grades
  #=> [5, 4, 5] 

We now simply form the hash that is the value of 'ST4' .我们现在简单地形成哈希值,即'ST4'的值。

c = points.sum
  #=> 35 
d = grades.sum
  #=> 14 
e = grades.size
  #=> 3 
f = c.fdiv(d)
  #=> 4.666666666666667 

The value of 'ST4' in student_data therefore maps to the hash因此, student_data'ST4'的值映射到哈希

{ :points=>c, :grades=>f }
  #=> {:points=>35, :grades=>4.666666666666667} 

The mappings of the remaining keys of student_data are computed similarly. student_data其余键的映射也是类似计算的。

See Hash#transform_values , Enumerable#map , Hash#values_at , Array#transpose , Array#sum and Integer#fdiv .参见Hash#transform_valuesEnumerable#mapHash#values_atArray#transposeArray#sumInteger#fdiv

Whatever you expect can be achieved as below,无论您期望什么都可以实现,如下所示,

student_data.values.map do |z|
  z.group_by { |x| x[:student_id] }.transform_values do |v|
    { 
      points: v.map { |x| x[:points] }.sum, # sum of points
      grade: (v.map { |x| x[:grade] }.sum/v.count.to_f).round(2) # average of grades
    }
  end
end

As exact expected output format is not specified, obtained in following way,由于没有指定确切的预期输出格式,通过以下方式获得,

=> [
  {"ST4"=>{:points=>35, :grade=>4.67}},
  {"ST1"=>{:points=>85, :grade=>3.0}},
  {"ST2"=>{:points=>75, :grade=>3.0}},
  {"ST3"=>{:points=>55, :grade=>3.5}}
]

For Ruby 2.6 using Object#then orObject#yield_self for Ruby 2.5对于Ruby 2.6使用Object#thenObject#yield_self for Ruby 2.5

student_data.transform_values { |st| st
  .each_with_object(Hash.new(0)) { |h, hh|  hh[:sum_points] += h[:points]; hh[:sum_grade] += h[:grade]; hh[:count] += 1.0 }
  .then{ |hh| {tot_points: hh[:sum_points], avg_grade: hh[:sum_grade]/hh[:count] } }
}


How it works? 这个怎么运作?

Given the array for each student:给定每个学生的数组:

 st = [{:student_id=>"ST4", :points=> 5, :grade=>5}, {:student_id=>"ST4", :points=>10, :grade=>4}, {:student_id=>"ST4", :points=>20, :grade=>5}]

First build a hash adding and counting using Enumerable#each_with_object with a Hash#default set at zero (Hash.new(0) )首先使用Enumerable#each_with_object构建哈希添加和计数, Hash#default Enumerable#each_with_object设置为零(Hash.new(0) )

 step1 = st.each_with_object(Hash.new(0)) { |h, hh| hh[:sum_points] += h[:points]; hh[:sum_grade] += h[:grade]; hh[:count] += 1.0 } #=> {:sum_points=>35, :sum_grade=>14, :count=>3.0}

Then use then!那就用吧! ( yield_self for Ruby 2.5) ( Ruby 2.5 的yield_self

 step2 = step1.then{ |hh| {tot_points: hh[:sum_points], avg_grade: hh[:sum_grade]/hh[:count] }} #=> {:tot_points=>35, :avg_grade=>4.666666666666667}

Put all together using Hash#transform_values as in the first snippet of code使用Hash#transform_values将所有内容放在一起,就像在第一个代码片段中一样

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用相同的键从多个哈希中添加多个值(Perl) - how to add multiple values from multiple hashes with same key (perl) 如何将两个不同散列数组的值一起添加? - How do I add values from two different arrays of hashes together? Ruby on Rails - Ruby,如何从具有相同键的两个散列中添加值,而不覆盖这些值? - Ruby on Rails - Ruby, How to add the values from two hashes with same key, without overwriting the values? 在哈希数组中添加相同Key的值 - Add values of same Key in array of hashes Ruby:我有两个哈希数组,如何计算两个哈希中具有相同ID的元素? - Ruby: I have two arrays of hashes, how do I count elements with the same id in both hashes? 如何将具有相同密钥的多个哈希分组为哈希数组 - How to group multiple hashes with same key into an array of hashes 如何在PHP中将某个键的值从两个数组添加到一个新数组中? - How do i add values of a certain key from two arrays into one new array in PHP? 如何从散列哈希中有效地提取具有某个键名的所有值? - How do I efficiently extract all values with a certain key name from a hash of hashes? 如何在同一个 position 中将多个字符串 Arrays 中的双精度值相加? C# - How do I add up Double Values from multiple String Arrays at the same position? C# 如何通过一个键对哈希数组进行分组以及合并内部键和数组 - How to group array of hashes by one key and merge inner keys and arrays
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM