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」はありますか?

私が望んでいたのは、次のような「unless then」演算子でした...

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: 考えられる解決策の 1 つ

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

この変更は、次の 1 つのケースのみを保護します。

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

この変更は、1 つのケースに対してのみ保護します。

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

より一般的には、ruby1.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 に答える