我试图让哈希和数组的结合点内为每个学生的总和和平均品位,但我所有的努力只返回一般总和的所有条目。有任何想法吗?
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}]}
无论你希望可以如下实现,
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
由于未指定确切预期的输出格式,在下面的方式获得,
=> [
{"ST4"=>{:points=>35, :grade=>4.67}},
{"ST1"=>{:points=>85, :grade=>3.0}},
{"ST2"=>{:points=>75, :grade=>3.0}},
{"ST3"=>{:points=>55, :grade=>3.5}}
]
所期望的散列可以正是如此获得。
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]
我们现在只是从是qazxsw POI值的哈希值。
'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}
的剩余键的映射类似地计算。
见qazxsw POI,qazxsw POI,qazxsw POI,student_data
,Hash#transform_values和Enumerable#map。
为Ruby 2.6使用Hash#values_at或Array#transpose为Ruby 2.5
Array#sum
鉴于阵列为每个学生:
Integer#fdiv
首先建立一个散列添加和使用Object#then
与Object#yield_self
组计数为零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] } }
}
)
st = [{:student_id=>"ST4", :points=> 5, :grade=>5}, {:student_id=>"ST4", :points=>10, :grade=>4}, {:student_id=>"ST4", :points=>20, :grade=>5}]
然后用呢! (Enumerable#each_with_object
为Ruby 2.5)
Hash#default
把所有一起使用(Hash.new(0)
作为代码的第一个片段