如何从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