我有一个哈希,其键是周数,值是出勤分数。我想根据周数来计算每个月的平均出勤率。
以下是哈希
的示例weekly_attendance = {31 => 40.0, 32 => 100.00, 33 => 34.00, 34 => 23.78, 35 => 56.79, 36 => 44.50, 37 => 67.00, 38 => 55.00 }
由于一个月包含4周且该月的开始周可被4整除,因此出勤率需按如下方式排序
第1个月的出勤时间为31,32周,即(40.00 + 100.00)/ 2 = 70.0
第2个月的出勤时间为33,34,35,36周 即(34.00 + 23.78 + 56.79 + 44.50)/ 4 = 39.5
第3个月的出勤率包括第37周,38周,即(67.00 + 55.00)/ 2 = 69.5
输出应为
monthly_attendance = [70.0,39.5,61]
我尝试过每个和选择方法,并使用模运算符条件,即周%4 == 0来添加出勤值。但无法根据月份对其进行有效分组
tmp = 0
monthly_attendance = []
weekly_attendance.select do |k,v|
tmp += v
monthly_attendance << tmp if k % 4 == 0
end
我无法使用上述代码对范围内的周数进行排序。
答案 0 :(得分:2)
您可以尝试这样的事情:
results = weekly_attendance.group_by { |week, value| (week + 3) / 4 }.map do |month, groups|
values = groups.map(&:last)
average = values.inject(0) { |sum, val| sum + val } / values.length
[month, average]
end.to_h
p results # {8=>70.0, 9=>39.7675, 10=>61.0}
但是将数周转换为数月的逻辑在这里是有缺陷的,最好使用一些日历函数而不是仅仅按4除。
您可以使用以下方式获取实际月份数字:
require 'date'
weekly_attendance.group_by { |week, value| Date.commercial(Time.now.year, week, 1).month }
但结果与您期望的结果不符,因为例如第31周是7月,而第32周是8月(今年),而不是像您预期的那样。
答案 1 :(得分:1)
我假设如果在给定的一周内生成x
个单位,则会在该周的每一天生成x/7
个单位。如果改变这个假设,下面的代码可以很容易地改变。
首先构造一个哈希,其键为月(1-12
),其值为哈希,其键为周,其值为给定月份给定周的天数。 (呼!)
require 'date'
def months_to_weeks(year)
day = Date.new(year)
days = day.leap? ? 365 : 364
days.times.with_object(Hash.new { |h,k| h[k] = Hash.new(0) }) do |_,h|
h[day.month][day.cweek] += 1
day = day.next
end
end
Hash#new的文档解释了该声明:
Hash.new { |h,k| h[k] = Hash.new(0) }
简而言之,这会创建一个空哈希,并使用块给出的默认值。如果h
是创建的哈希,并且h
没有密钥k
,h[k]
将导致执行该块,这会将该密钥添加到哈希并将其值设置为空哈希值,默认值为0
。后一个散列通常被称为“计数散列”。我意识到这对于一个Ruby新手来说还是相当满口。
让我们为当前年份生成此哈希:
year = 2015
mon_to_wks = months_to_weeks(year)
#=> {1 =>{1 =>4, 2 =>7, 3 =>7, 4 =>7, 5=>6},
# 2 =>{5 =>1, 6 =>7, 7 =>7, 8 =>7, 9=>6},
# 3 =>{9 =>1, 10=>7, 11=>7, 12=>7, 13=>7, 14=>2},
# 4 =>{14=>5, 15=>7, 16=>7, 17=>7, 18=>4},
# 5 =>{18=>3, 19=>7, 20=>7, 21=>7, 22=>7},
# 6 =>{23=>7, 24=>7, 25=>7, 26=>7, 27=>2},
# 7 =>{27=>5, 28=>7, 29=>7, 30=>7, 31=>5},
# 8 =>{31=>2, 32=>7, 33=>7, 34=>7, 35=>7, 36=>1},
# 9 =>{36=>6, 37=>7, 38=>7, 39=>7, 40=>3},
# 10=>{40=>4, 41=>7, 42=>7, 43=>7, 44=>6},
# 11=>{44=>1, 45=>7, 46=>7, 47=>7, 48=>7, 49=>1},
# 12=>{49=>6, 50=>7, 51=>7, 52=>7, 53=>3}}
由于Date#cweek的定义方式,此哈希中的周数从星期一开始。例如,在1月份,4
天是1
天。这四天,即2015年1月1日至4日,将是2015年的第一个周四,周五,周六和周日。(查看您的日历。)
如果每周的第一天是星期一(例如星期日)以外的日子,则必须稍微改变哈希计算。
这表明,例如,在2015年1月,一周中4
天1
,7
天,2
,3
一周4
和6
天5
。一周剩余的一天5
是二月的第一天。
一旦构建了这个哈希,计算每个月的平均值就很简单了:
weekly_attendance = {31 => 40.00, 32 => 100.00, 33 => 34.00, 34 => 23.78,
35 => 56.79, 36 => 44.50, 37 => 67.00, 38 => 55.00 }
prod_by_mon = (1..12).each_with_object(Hash.new(0)) do |i,h|
mon_to_wks[i].each do |week, days|
h[i] += (days/7.0)*weekly_attendance[week] if weekly_attendance.key?(week)
end
end
#=> {7=>28.571428571428573, 8=>232.3557142857143, 9=>160.14285714285714}
prod_by_mon.merge(prod_by_mon) { |_,v| v.round(2) }
#=> {7=>28.57, 8=>232.36, 9=>160.14}
这表明月7
的生产期为27.57
,依此类推。请注意:
28.57 + 232.36 + 160.14 #=> 421.07
weekly_attendance.values.reduce(:+) #=> 421.07