una separate rails programar porque paul numero metodo infinito indeterminada example español error entre edición edicion dividir dividido deitel cuanto cuando completo como cero 10ª ruby refactoring divide-by-zero

separate - split in ruby example



Ruby way: captura la división por cero. (8)

Tengo el siguiente método para calcular un promedio:

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

No es nada especial, pero tiene un problema que espero que tengan todas las ecuaciones promedio: podría dividirse por cero si todas las entradas son cero.

Entonces, pensé en hacer esto:

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

... y eso funciona, pero a mí me parece una tontería. ¿Hay una forma más elegante, "Ruby Way" para evitar esta división por cero problema?

Lo que desearía tener era un operador "a menos que entonces", como ...

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

¿Alguna sugerencia?


TL; DR: Una posible solución

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

Esto protege contra todos los casos:

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

Función original:

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

Considere verificar si hay cero:

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

Este cambio solo protege contra un caso:

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)

Considere usar un rescue línea

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

Este cambio solo protege contra un caso, también:

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)

Usar un rescue línea tiene otra consecuencia. Considere este error tipográfico:

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

Considera usar un 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

Esto es mejor, ya que no oculta errores, pero protege contra el mismo escenario que el rescue inclinación anterior.

Otra versión con lo que yo llamaría un cálculo promedio normal.

Como nota al margen, la operación promedio con la que estoy familiarizado se calcula usando total / count, así que aquí hay una versión que lo hace.

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

Esto protege contra todos los casos:

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


¿Puedes usar el nonzero? , como en:

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

Más personas estarían más familiarizadas con el uso del operador ternario (total == 0 ? 1 : total) , por lo que esa es otra posibilidad.


Es común confiar en el rescue para capturar la excepción y luego devolver el valor predeterminado:

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

También escribiría:

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

como

average = (denominator == 0) ? 0 : numerator / denominator


No soy muy Rubista, pero lo haría así:

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

Probablemente hay una mejor respuesta, pero esto podría ser suficiente.


Para mí, la forma más limpia es:

numerator / denominator rescue 0

También le ahorra el manejo de 0/0.

Como @Andrew señala, esto solo es válido para enteros. Ver los comentarios a esta respuesta para más información.


Si bien este es un hilo desactualizado, pensé que estaría de acuerdo con un simple forro que puedes usar ...

@average = variable1 / variable2 rescue 0


/ no devuelve un error de división cero si el número a dividir o el denominador es un flotante.

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

Más generalmente, bajo 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


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