我正在尝试实现一个累积加权平均函数,该函数作为参数 列表
[[1000, 3.1], [500, 1.2], [800, 7.1], [1300, 8.88]]
并返回(在此处四舍五入到小数点后两位)
[3.1, 2.47, 4.08, 5.81]
例如:2.47 =(1000 * 3.1 + 500 * 1.2)/ 1500。
我目前使用以下代码解决了这个问题:
def cumulative_weighted_average(list)
cs = 0
qu = 0
res = list.inject([0]) do |s, el|
cs += el[0] * el[1]
qu += el[0]
s + [cs.to_f / qu]
end
res.shift
res
end
是否有更短(更紧凑)的方式?
修改 感谢下面的答案!该列表平均包含大约1000个条目,因此不确定速度要求。由于我需要能够在块内实际跟踪两个值,是否有一些注入的扩展允许您编写
list.inject([0,0]){ |s1, s2, el| ...}
其中s1和s2初始化为0?
答案 0 :(得分:5)
我认为这就是你想要的:
def cumulative_weighted_average list
cs, qu = 0.0, 0.0
list
.map{|x, w| [cs += x * w, qu += x]}
.map{|cs, qu| cs / qu}
end
cumulative_weighted_average([[1000, 3.1], [500, 1.2], [800, 7.1], [1300, 8.88]])
# => [3.1, 2.466666666666667, 4.078260869565217, 5.812222222222222]
<小时/> 对于其他问题,可以这样做:
list.inject([0,0]){|(s1, s2), el| ...}
答案 1 :(得分:2)
这样做是否有缩短(更紧凑)的方式?
我可以试试你..
arr = [[1000, 3.1], [500, 1.2], [800, 7.1], [1300, 8.88]]
arr2 = (1..arr.size).map do |i|
b = arr.take(i)
b.reduce(0){|sum,a| sum + a.reduce(:*)}/b.reduce(0){|sum,k| sum + k[0]}
end
arr2
# => [3.1, 2.466666666666667, 4.078260869565217, 5.812222222222222]
答案 2 :(得分:0)
你可以避免使用“外部”临时变量,并使事情看起来更清晰,并且惯用Ruby,如果你允许进行两阶段计算(这不一定比较慢,涉及相同数量的数学): / p>
def cumulative_weighted_average list
cumulative_totals = list.inject( [] ) do |cumulative,item|
tot_count, tot_sum = cumulative.last || [0, 0.0]
next_count, next_value = item
cumulative << [ tot_count + next_count, tot_sum + next_count * next_value ]
end
cumulative_totals.map { |count,sum| sum/count }
end
p cumulative_weighted_average(
[[1000, 3.1], [500, 1.2], [800, 7.1], [1300, 8.88]] )
=> [3.1, 2.46666666666667, 4.07826086956522, 5.81222222222222]