如何从数组中求平均值?
如果我有一个数组:
[0,4,8,2,5,0,2,6]
平均得到3.375。
如何从数组中求平均值?
如果我有一个数组:
[0,4,8,2,5,0,2,6]
平均得到3.375。
当前回答
class Array
def sum
inject( nil ) { |sum,x| sum ? sum+x : x }
end
def mean
sum.to_f / size.to_f
end
end
[0,4,8,2,5,0,2,6].mean
其他回答
您可以根据需要选择以下解决方案之一。
Bruteforce
[0,4,8,2,5,0,2,6].sum.to_f / [0,4,8,2,5,0,2,6].size.to_f
=> 3.375
方法
def avg(array)
array.sum.to_f / array.size.to_f
end
avg([0,4,8,2,5,0,2,6])
=> 3.375
猴子打补丁
class Array
def avg
sum.to_f / size.to_f
end
end
[0,4,8,2,5,0,2,6].avg
=> 3.375
但我不建议对Array类进行猴子补丁,这种做法是危险的,可能会对您的系统造成不良影响。
为了我们的好处,ruby语言提供了一个很好的特性来克服这个问题,即Refinements,这是一种安全的方法来对ruby进行monkey补丁。
为了简化,使用细化,您可以猴子修补数组类,并且更改将只在使用细化的类范围内可用!:)
您可以在您正在处理的类中使用细化,并且您已经准备好了。
细化
module ArrayRefinements
refine Array do
def avg
sum.to_f / size.to_f
end
end
end
class MyClass
using ArrayRefinements
def test(array)
array.avg
end
end
MyClass.new.test([0,4,8,2,5,0,2,6])
=> 3.375
Ruby版本>= 2.4有一个Enumerable#sum方法。
要获得浮点平均值,可以使用Integer#fdiv
arr = [0,4,8,2,5,0,2,6]
arr.sum.fdiv(arr.size)
# => 3.375
对于旧版本:
arr.reduce(:+).fdiv(arr.size)
# => 3.375
一些顶级解决方案的基准测试(按效率最高的顺序排列):
大阵:
array = (1..10_000_000).to_a
Benchmark.bm do |bm|
bm.report { array.instance_eval { reduce(:+) / size.to_f } }
bm.report { array.sum.fdiv(array.size) }
bm.report { array.sum / array.size.to_f }
bm.report { array.reduce(:+).to_f / array.size }
bm.report { array.reduce(:+).try(:to_f).try(:/, array.size) }
bm.report { array.inject(0.0) { |sum, el| sum + el }.to_f / array.size }
bm.report { array.reduce([ 0.0, 0 ]) { |(s, c), e| [ s + e, c + 1 ] }.reduce(:/) }
end
user system total real
0.480000 0.000000 0.480000 (0.473920)
0.500000 0.000000 0.500000 (0.502158)
0.500000 0.000000 0.500000 (0.508075)
0.510000 0.000000 0.510000 (0.512600)
0.520000 0.000000 0.520000 (0.516096)
0.760000 0.000000 0.760000 (0.767743)
1.530000 0.000000 1.530000 (1.534404)
小数组:
array = Array.new(10) { rand(0.5..2.0) }
Benchmark.bm do |bm|
bm.report { 1_000_000.times { array.reduce(:+).to_f / array.size } }
bm.report { 1_000_000.times { array.sum / array.size.to_f } }
bm.report { 1_000_000.times { array.sum.fdiv(array.size) } }
bm.report { 1_000_000.times { array.inject(0.0) { |sum, el| sum + el }.to_f / array.size } }
bm.report { 1_000_000.times { array.instance_eval { reduce(:+) / size.to_f } } }
bm.report { 1_000_000.times { array.reduce(:+).try(:to_f).try(:/, array.size) } }
bm.report { 1_000_000.times { array.reduce([ 0.0, 0 ]) { |(s, c), e| [ s + e, c + 1 ] }.reduce(:/) } }
end
user system total real
0.760000 0.000000 0.760000 (0.760353)
0.870000 0.000000 0.870000 (0.876087)
0.900000 0.000000 0.900000 (0.901102)
0.920000 0.000000 0.920000 (0.920888)
0.950000 0.000000 0.950000 (0.952842)
1.690000 0.000000 1.690000 (1.694117)
1.840000 0.010000 1.850000 (1.845623)
a = [0,4,8,2,5,0,2,6]
sum = 0
a.each { |b| sum += b }
average = sum / a.length
这个方法很有用。
def avg(arr)
val = 0.0
arr.each do |n|
val += n
end
len = arr.length
val / len
end
p avg([0,4,8,2,5,0,2,6])