Требуемый хэш может быть получен таким образом.
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}}
Первое значение, переданное блоку, является значением первого ключа, '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}]
Расчеты блока выполняются следующим образом.Первое значение arr
, переданное map
во внутренний блок, равно
h = arr.first
#=> {:student_id=>"ST4", :points=>5, :grade=>5}
h.values_at(:points, :grade)
#=> [5, 5]
После того, как оставшиеся два элемента arr
переданы в блок, мы имеем
b = arr.map { |h| h.values_at(:points, :grade) }
#=> [[5, 5], [10, 4], [20, 5]]
Тогда
points, grades = b.transpose
#=> [[5, 10, 20], [5, 4, 5]]
points
#=> [5, 10, 20]
grades
#=> [5, 4, 5]
Теперь мы просто формируем хеш, который является значением 'ST4'
.
c = points.sum
#=> 35
d = grades.sum
#=> 14
e = grades.size
#=> 3
f = c.fdiv(d)
#=> 4.666666666666667
Значение 'ST4'
в student_data
, следовательно, отображается в хеш
{ :points=>c, :grades=>f }
#=> {:points=>35, :grades=>4.666666666666667}
Отображения остальных ключей student_data
вычисляются аналогично.
См. Hash # transform_values , Enumerable # map , Hash # values_at , Array # transpose , Array # sum и Integer # fdiv .