如何从Ruby数组创build平均值?

如何从数组中find平均值?

如果我有arrays:

[0,4,8,2,5,0,2,6] 

平均会给我3.375。

谢谢!

尝试这个:

 arr = [5, 6, 7, 8] arr.inject{ |sum, el| sum + el }.to_f / arr.size => 6.5 

请注意.to_f ,这是为了避免整数除法的问题。 你也可以这样做:

 arr = [5, 6, 7, 8] arr.inject(0.0) { |sum, el| sum + el } / arr.size => 6.5 

您可以将其定义为另一个评论者所build议的Array一部分,但是您需要避免整数划分,否则结果将会错误。 此外,这通常不适用于每种可能的元素types(显然,平均值只对可以平均的东西有意义)。 但是,如果你想要走这条路线,就用这个:

 class Array def sum inject(0.0) { |result, el| result + el } end def mean sum / size end end 

如果你之前没有看到inject ,那么它就不像它看起来那么神奇。 它迭代每个元素,然后将累加器值应用到它。 累加器然后交给下一个元素。 在这种情况下,我们的累加器只是一个反映所有以前元素之和的整数。

编辑:评论家戴夫雷提出了一个很好的改进。

编辑:评论者格伦·杰克曼的build议,使用arr.inject(:+).to_f ,也不错,但如果你不知道发生了什么,也许有点太聪明了。 :+是一个符号; 当通过注入时,它会将符号所指定的方法(在这种情况下是加法运算)应用于每个元素的累加器值。

 a = [0,4,8,2,5,0,2,6] a.instance_eval { reduce(:+) / size.to_f } #=> 3.375 

这个不使用instance_eval版本是:

 a = [0,4,8,2,5,0,2,6] a.reduce(:+) / a.size.to_f #=> 3.375 

我相信最简单的答案是

 list.reduce(:+).to_f / list.size 

我希望Math.average(值),但没有这样的运气。

 values = [0,4,8,2,5,0,2,6] average = values.sum / values.size.to_f 

为了公共娱乐,还有另一个解决scheme:

 a = 0, 4, 8, 2, 5, 0, 2, 6 a.reduce [ 0.0, 0 ] do |(s, c), e| [ s + e, c + 1 ] end.reduce :/ #=> 3.375 

让我把一些东西带入竞争,解决零分问题:

 a = [1,2,3,4,5,6,7,8] a.reduce(:+).try(:to_f).try(:/,a.size) #==> 4.5 a = [] a.reduce(:+).try(:to_f).try(:/,a.size) #==> nil 

不过,我必须承认,“尝试”是Rails的帮手。 但是你可以轻松解决这个问题:

 class Object;def try(*options);self&&send(*options);end;end class Array;def avg;reduce(:+).try(:to_f).try(:/,size);end;end 

顺便说一句:我认为空列表的平均值为零是正确的。 没有什么的平均值不是0,所以这是预期的行为。 但是,如果您更改为:

 class Array;def avg;reduce(0.0,:+).try(:/,size);end;end 

空arrays的结果不会像我所预期的那样是一个例外,但是它会返回NaN …我从来没有在Ruby中看到过。 ;-)似乎是Float类的特殊行为…

 0.0/0 #==> NaN 0.1/0 #==> Infinity 0.0.class #==> Float 
 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 

Ruby 2.4有一个Enumerable#sum方法。

而要获得浮点平均值,可以使用Integer#fdiv

 arr = [0,4,8,2,5,0,2,6] arr.sum.fdiv(arr.size) # => 3.375 
 a = [0,4,8,2,5,0,2,6] sum = 0 a.each { |b| sum += b } average = sum / a.length 

我不喜欢接受的解决scheme

 arr = [5, 6, 7, 8] arr.inject{ |sum, el| sum + el }.to_f / arr.size => 6.5 

是不是真的以纯粹的function方式工作。 我们需要一个variablesarr来计算最后的arr.size。

为了解决这个纯粹的function,我们需要跟踪两个值:所有元素的总和和元素的数量。

 [5, 6, 7, 8].inject([0.0,0]) do |r,ele| [ r[0]+ele, r[1]+1 ] end.inject(:/) => 6.5 

如果你想看看它是如何工作的,添加一些put:

 [5, 6, 7, 8].inject([0.0,0]) do |r,ele| r2 = [ r[0]+ele, r[1]+1 ] puts "adding #{ele} gives #{r2}" r2 end.inject(:/) adding 5 gives [5.0, 1] adding 6 gives [11.0, 2] adding 7 gives [18.0, 3] adding 8 gives [26.0, 4] => 6.5 

如果你使用一个结构而不是一个数组来包含总和和计数,那么它更可读,但是你必须首先声明结构:

 R=Struct.new(:sum, :count) [5, 6, 7, 8].inject( R.new(0.0, 0) ) do |r,ele| r.sum+=ele r.count+=1 r end.inject(:/) 
 a = [0,4,8,2,5,0,2,6] a.empty? ? nil : a.reduce(:+)/a.size.to_f => 3.375 

解除零,整数除法,易于阅读。 可以很容易地修改,如果你select有一个空数组返回0。

我也喜欢这个变体,但是它更罗嗦一点。

 a = [0,4,8,2,5,0,2,6] a.empty? ? nil : [a.reduce(:+), a.size.to_f].reduce(:/) => 3.375 

arr = [0,4,8,2,5,0,2,6] average = arr.inject(&:+).to_f / arr.size => 3.375

在这台电脑上没有ruby,但是在这个范围内应该可以工作:

 values = [0,4,8,2,5,0,2,6] total = 0.0 values.each do |val| total += val end average = total/values.size 

你可以尝试如下的东西:

 2.0.0-p648 :009 > a = [1,2,3,4,5] => [1, 2, 3, 4, 5] 2.0.0-p648 :010 > (a.sum/a.length).to_f => 3.0 
 [1,2].tap { |a| @asize = a.size }.inject(:+).to_f/@asize 

简短但使用实例variables