23

我有以下方法来计算平均值:

def compute_average(a,b,c,d,e)
  total = [a,b,c,d,e].sum.to_f
  average = [a, 2*b, 3*c, 4*d, 5*e].sum / total
  average.round(2)
end

这没什么特别的,但它有一个我希望所有平均方程都有的问题:如果输入全为零,它可能会被零除。

所以,我想到了这样做:

def compute_average(a,b,c,d,e)
  total = [a,b,c,d,e].sum.to_f
  if total==0
    average = 0.00
  else
    average = [a, 2*b, 3*c, 4*d, 5*e].sum / total
    average.round(2)
  end
end

……这行得通,但对我来说感觉很笨拙。有没有更优雅的“Ruby Way”来避免这种被零除的问题?

我希望我拥有的是一个“除非那时”操作员,比如......

average = numerator / denominator unless denominator == 0 then 0

有什么建议么?

4

8 回答 8

69

您可以使用nonzero?,如:

def compute_average(a,b,c,d,e)
  total = [a,b,c,d,e].sum.to_f
  average = [a, 2*b, 3*c, 4*d, 5*e].sum / (total.nonzero? || 1)
end

更多的人会更熟悉使用三元运算符(total == 0 ? 1 : total),所以这是另一种可能性。

于 2011-04-03T16:53:30.097 回答
7

通常依靠rescue捕获异常,然后返回默认值:

def compute_average(a, b, c, d, e)
  total = [a, b, c, d, e].sum.to_f
  average = [ a, 2*b, 3*c, 4*d, 5*e ].sum / total
  average.round(2)
  rescue ZeroDivisionError
    0.0
end

另外我会写:

average = numerator / denominator unless denominator == 0 then 0

作为

average = (denominator == 0) ? 0 : numerator / denominator
于 2011-04-04T05:16:23.103 回答
4

虽然这是一个过时的线程,但我想我会用一个你可以使用的简单的衬里来插话……

@average = variable1 / variable2 rescue 0
于 2014-12-15T10:23:10.607 回答
3
def compute_average(a,b,c,d,e)
  total = (a+b+c+d+e).to_f
  total.zero? ? 0 : ((a + 2*b + 3*c + 4*d + 5*e) / total).round(2)
end
于 2011-04-03T16:53:39.893 回答
3

对我来说,最干净的方法是:

numerator / denominator rescue 0

它还使您免于处理0 / 0.

正如@Andrew 指出的那样,这仅对整数有效。有关更多信息,请参阅对此答案的评论。

于 2013-12-20T04:18:46.140 回答
1

TL;DR:一种可能的解决方案

def compute_average(*values)

  # This makes sure arrays get flattened to a single array.
  values.flatten!

  # Throws away all nil values passed as arguments.
  values.reject!(&:nil?)

  # Throws away all non-numeric values.
  # This includes trashing strings that look like numbers, like "12".
  values.keep_if{ |v| v.is_a? Numeric }

  total = values.sum.to_f
  return Float::NAN if total.zero?

  # I'm not sure what this business is
  #   average = [a, 2*b, 3*c, 4*d, 5*e].sum / total
  # but it can be translated to
  average = values.each_with_index.map{ |v,i| v*(i+1) }.sum / total

  average.round(2)
end

这可以防止所有情况:

compute_average(1,2,3,4,5)
=> 3.67

compute_average(0,0,0,0,0)
=> NaN

compute_average(1,2,nil,4,5)
=> 3.08

compute_average(1,2,"string",4,5)
=> 3.08

compute_average(1)
=> 1.0

compute_average([1,2,3,4,5])
=> 3.67

compute_average
=> NaN

原始功能:

def compute_average(a,b,c,d,e)
  total = [a,b,c,d,e].sum.to_f
  average = [a, 2*b, 3*c, 4*d, 5*e].sum / total
  average.round(2)
end

考虑检查零:

def compute_average(a,b,c,d,e)
  total = [a,b,c,d,e].sum.to_f
  return if total.zero?
  average = [a, 2*b, 3*c, 4*d, 5*e].sum / total
  average.round(2)
end

此更改仅可防止一种情况:

compute_average(1,2,3,4,5)
# => 3.67

compute_average(0,0,0,0,0)
# => nil

compute_average(1,2,nil,4,5)
# => TypeError: NilClass can't be coerced into Fixnum

compute_average(1,2,"string",4,5)
# => TypeError: String can't be coerced into Fixnum

compute_average(1)
# => ArgumentError: wrong number of arguments calling `compute_average` (1 for 5)

compute_average([1,2,3,4,5])
# => ArgumentError: wrong number of arguments calling `compute_average` (1 for 5)

compute_average
# => ArgumentError: wrong number of arguments calling `compute_average` (0 for 5)

考虑使用内联rescue

def compute_average(a,b,c,d,e)
  total = [a,b,c,d,e].sum.to_f
  average = [a, 2*b, 3*c, 4*d, 5*e].sum / total rescue 0
  average.round(2)
end

此更改仅可防止一种情况,还:

compute_average(1,2,3,4,5)
# => 3.67

compute_average(0,0,0,0,0)
# => NaN

compute_average(1,2,nil,4,5)
# => TypeError: NilClass can't be coerced into Fixnum

compute_average(1,2,"string",4,5)
# => TypeError: String can't be coerced into Fixnum

compute_average(1)
# => ArgumentError: wrong number of arguments calling `compute_average` (1 for 5)

compute_average([1,2,3,4,5])
# => ArgumentError: wrong number of arguments calling `compute_average` (1 for 5)

compute_average
# => ArgumentError: wrong number of arguments calling `compute_average` (0 for 5)

使用内联rescue有另一个后果。考虑这个错字:

def compute_average(a,b,c,d,e)
  total = [a,b,c,d,e].sum.to_f
  average = [a, 2*b, 3*c, 4*d, 5*e].smu / total rescue 0
  #                                 ^^^
  average.round(2)
end

compute_average(1,2,3,4,5)
# => 0.0

compute_average(0,0,0,0,0)
# => 0.0

考虑使用一个rescue

def compute_average(a,b,c,d,e)
  total = [a,b,c,d,e].sum.to_f
  average = [a, 2*b, 3*c, 4*d, 5*e].sum / total
  average.round(2)
rescue ZeroDivisionError
  0.0
end

这更好,因为它不会隐藏错误,但可以防止与上述倾斜相同的情况rescue

另一个我称之为正常平均计算的版本

作为旁注,我熟悉的平均操作是使用总数/计数计算的,所以这里有一个版本可以做到这一点。

def compute_average(*values)

  # This makes sure arrays get flattened to a single array.
  values.flatten!

  # Throws away all nil values passed as arguments.
  values.reject!(&:nil?)

  # Throws away all non-numeric values.
  # This includes trashing strings that look like numbers, like "12".
  values.keep_if{ |v| v.is_a? Numeric }

  total = values.sum.to_f
  count = values.count
  return Float::NAN if count.zero?

  total / count
end

这可以防止所有情况:

compute_average(1,2,3,4,5)
=> 3.0

compute_average(0,0,0,0,0)
=> 0.0

compute_average(1,2,nil,4,5)
=> 3.0

compute_average(1,2,"string",4,5)
=> 3.0

compute_average(1)
=> 1.0

compute_average([1,2,3,4,5])
=> 3.0

compute_average
=> NaN
于 2014-11-10T22:34:21.250 回答
0

我不是一个 Ruby 主义者,但我会这样做:

average = denominator.nonzero? ? numerator/denominator : 0

可能有更好的答案,但这可能就足够了。

于 2011-04-03T16:54:05.613 回答
0

/如果要除的数字或分母是浮点数,则不返回除零错误。

def compute_average(a,b,c,d,e)
  total = [a,b,c,d,e].sum.to_f
  average = [a, 2*b, 3*c, 4*d, 5*e].sum / total
  average.finite? ? average.round(2) : 0.0
end

更一般地说,在 ruby​​1.9 下,

def compute_average *args
  average = args.to_enum.with_index.map{|x, w| x * w}.sum / args.sum.to_f
  average.finite? ? average.round(2) : 0.0
end
于 2011-04-03T16:58:28.330 回答