如何从阵列中找到平均值?
如果我有阵列:
[0,4,8,2,5,0,2,6]
平均值会给我3.375。
谢谢!
答案 0 :(得分:244)
试试这个:
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
您可以将其定义为另一位评论者建议的Array
的一部分,但您需要避免整数除法,否则您的结果将会出错。此外,这通常不适用于每种可能的元素类型(显然,平均值仅对可以平均的事物有意义)。但是如果你想走这条路,请使用:
class Array
def sum
inject(0.0) { |result, el| result + el }
end
def mean
sum / size
end
end
如果您之前没有看过inject
,那就不像它看起来那么神奇了。它迭代每个元素,然后将累加器值应用于它。然后将累加器传递给下一个元素。在这种情况下,我们的累加器只是一个整数,它反映了所有先前元素的总和。
编辑:评论员Dave Ray提出了一个很好的改进。
编辑:评论员格伦·杰克曼的提议,使用arr.inject(:+).to_f
,也很不错,但如果你不知道发生了什么,也许有点太聪明了。 :+
是一个符号;当传递给inject时,它将符号命名的方法(在本例中为加法运算)应用于累加器值。
答案 1 :(得分:106)
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
答案 2 :(得分:88)
我相信最简单的答案是
list.reduce(:+).to_f / list.size
答案 3 :(得分:45)
我希望获得Math.average(值),但没有这样的运气。
values = [0,4,8,2,5,0,2,6]
average = values.sum / values.size.to_f
答案 4 :(得分:28)
Ruby版本> = 2.4具有Enumerable#sum方法。
要获得浮点平均值,您可以使用Integer#fdiv
file = open("read_it.txt" , "r")
for line in file:
line = line.strip('\n')
print(line)
total=[]
GTIN=''
while True:
GTIN=(input("please enter GTIN for product"))
if GTIN.isnumeric() and len(GTIN)==8 and GTIN in open('read_it.txt').read():
total.append(GTIN)
Quantity=""
while True:
Quantity=(input("Please enter the Quantity"))
if Quantity.isdigit():
break
else:
print("enter a number!")
else:
print("Product Not Found")
break
with open("read_it.txt", "r") as text_file:
for items in text_file:
line = items.strip('\r\n').split(",")
if GTIN in items:
allprice=[]
product = line[1]
indprice = line[2]
finprice = float(indprice)* float(Quantity)
print(GTIN,product,Quantity,"£",indprice,"£",finprice)
finprice=int(finprice)
total.append(finprice)
allprice.append(finprice)
break
# if user press key :
# final = sum(allprice)
# print(final)
对于旧版本:
arr = [0,4,8,2,5,0,2,6]
arr.sum.fdiv(arr.size)
# => 3.375
答案 5 :(得分:6)
顶级解决方案的一些基准测试(按照最有效的顺序):
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)
答案 6 :(得分:4)
为了公共娱乐,还有另一种解决方案:
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
答案 7 :(得分:4)
让我把一些东西带入竞争中,解决零问题的划分:
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
但是,我必须承认,“try”是一个Rails助手。但你可以很容易地解决这个问题:
class Object;def try(*options);self&&send(*options);end;end
class Array;def avg;reduce(:+).try(:to_f).try(:/,size);end;end
BTW:我认为空列表的平均值为零是正确的。没有什么是平均值,不是0.所以这是预期的行为。但是,如果您更改为:
class Array;def avg;reduce(0.0,:+).try(:/,size);end;end
空数组的结果不会像我预期的那样异常,而是返回NaN ......我以前从未在Ruby中看过它。 ;-)似乎是Float类的特殊行为......
0.0/0 #==> NaN
0.1/0 #==> Infinity
0.0.class #==> Float
答案 8 :(得分:3)
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
答案 9 :(得分:3)
无需重复数组(例如,非常适合单线):
[1, 2, 3, 4].then { |a| a.sum.to_f / a.size }
答案 10 :(得分:3)
我不喜欢接受的解决方案
arr = [5, 6, 7, 8]
arr.inject{ |sum, el| sum + el }.to_f / arr.size
=> 6.5
它实际上并不是以纯粹的功能方式工作。 我们需要一个变量arr来计算最后的arr.size。
要从纯粹的功能上解决这个问题,我们需要跟踪两个 values:所有元素的总和,以及元素的数量。
[5, 6, 7, 8].inject([0.0,0]) do |r,ele|
[ r[0]+ele, r[1]+1 ]
end.inject(:/)
=> 6.5
Santhosh改进了这个解决方案:我们可以使用解构来立即将它分成两个变量,而不是参数r是一个数组
[5, 6, 7, 8].inject([0.0,0]) do |(sum, size), ele|
[ sum + ele, size + 1 ]
end.inject(:/)
如果你想看看它是如何工作的,可以添加一些看跌期权:
[5, 6, 7, 8].inject([0.0,0]) do |(sum, size), ele|
r2 = [ sum + ele, size + 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
我们也可以使用struct而不是数组来包含sum和count,但是我们必须首先声明struct:
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(:/)
答案 11 :(得分:2)
另一个简单的解决方案
arr = [0,4,8,2,5,0,2,6]
arr.sum(0.0) / arr.size
答案 12 :(得分:2)
这台电脑上没有红宝石,但这种程度的东西应该有效:
values = [0,4,8,2,5,0,2,6]
total = 0.0
values.each do |val|
total += val
end
average = total/values.size
答案 13 :(得分:1)
arr = [0,4,8,2,5,0,2,6]
average = arr.inject(&:+).to_f / arr.size
=> 3.375
答案 14 :(得分:1)
Array#average
。我经常做同样的事情,所以我认为用简单的Array
方法扩展average
类是明智的。除了整数,浮点数或小数之类的数字数组外,它对其他任何功能均不起作用,但正确使用它会很方便。
我正在使用Ruby on Rails,因此已将其放置在config/initializers/array.rb
中,但是您可以将其放置在引导等包含的任何位置。
config/initializers/array.rb
class Array
# Will only work for an Array of numbers like Integers, Floats or Decimals.
#
# Throws various errors when trying to call it on an Array of other types, like Strings.
# Returns nil for an empty Array.
#
def average
return nil if self.empty?
self.sum / self.size
end
end
答案 15 :(得分:1)
此方法可能会有所帮助。
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])
答案 16 :(得分:1)
a = [0,4,8,2,5,0,2,6]
a.empty? ? nil : a.reduce(:+)/a.size.to_f
=> 3.375
解除零,整数除法,易于阅读。如果您选择让空数组返回0,则可以轻松修改。
我也喜欢这个变体,但它有点罗嗦。
a = [0,4,8,2,5,0,2,6]
a.empty? ? nil : [a.reduce(:+), a.size.to_f].reduce(:/)
=> 3.375
答案 17 :(得分:1)
a = [0,4,8,2,5,0,2,6]
sum = 0
a.each { |b| sum += b }
average = sum / a.length
答案 18 :(得分:0)
您可以尝试以下内容:
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
答案 19 :(得分:0)
print array.sum / array.count是我做的方式
答案 20 :(得分:0)
您可以根据需要选择以下解决方案之一。
[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类,这种做法很危险,并且可能对您的系统造成不良影响。
对于我们来说,红宝石语言提供了一个很好的功能来克服此问题,即优化,这是在红宝石上修补猴子的安全方法。
为简化起见,使用Refinements可以对Array
类进行猴子补丁,并且更改将仅在使用细化的类范围内可用! :)
您可以在正在从事的课程中使用改进,然后就可以开始学习了。
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
答案 21 :(得分:0)
我真的很喜欢定义一个 mean()
方法,以便我的代码更具表现力。
我通常想默认忽略 nil
,所以这是我定义的
def mean(arr)
arr.compact.inject{ |sum, el| sum + el }.to_f / arr.compact.size
end
mean([1, nil, 5])
=> 3.0
如果您想保留 nil
,只需删除两个.compact
。
答案 22 :(得分:0)
比 .inject 更快的解决方案是:
<块引用>arr.sum(0.0) / arr.size
参考这篇文章:https://andycroll.com/ruby/calculate-a-mean-average-from-a-ruby-array/
答案 23 :(得分:-1)
[1,2].tap { |a| @asize = a.size }.inject(:+).to_f/@asize
短但使用实例变量