在Ruby中编写此计算的最佳方法是什么?

3
什么是在Ruby中编写此计算的最佳方法?
amt = self.alt_inv - (self.alt_tax ? self.alt_tax : 0)
    - (self.alt_freight ? self.alt_freight : 0)
    - (self.misc1_amt ? self.misc1_amt : 0)
    - (self.misc2_amt ? self.misc2_amt : 0)
7个回答

8
在Ruby中,如果某个值不是nil,在布尔表达式中它将返回true,在计算中它将返回其值。
我没有很好地解释它,但你可以像这样做:
amt = alt_inv - 
  (alt_tax     || 0) -
  (alt_freight || 0) -
  (misc1_amt   || 0) -
  (misc2_amt   || 0)

这是一种更简洁的方法来完成你最初使用的三元运算符。


编辑:

实际上,我更喜欢Jed Schneider的答案。我不会在这里复制它,因为他的答案因其优雅而值得点赞。


6

由于amt是所有属性之和与alt_inv之差,因此您可以对扣除进行求和,然后从alt_inv中减去。 reduce提供了一种简洁的方法来实现此目的。 在执行缩减之前,compact会删除任何nil值。

当然,在这种情况下,属性可以根据您的需求进行扩展,甚至可以根据数据动态创建,并且在实际生活中,我显然不会使用变量属性。

attributes = [alt_tax, alt_freight, misc1_amt, misc2amt]
amt = alt_inv - attributes.compact.reduce(:+)

reduce: http://apidock.com/ruby/Enumerable/reduce

reduce是一个Ruby枚举器(Enumerable)的方法,它可以将一个集合中的元素通过指定的操作符进行迭代计算,并返回最终结果。

compact: http://apidock.com/ruby/Array/compact

compact是一个Ruby数组(Array)的方法,它可以移除数组中的所有nil元素,并返回一个新的数组。


我认为这是不必要的复杂。 - AboutRuby
在我看来,使用四个“或”语句(或者更糟糕的四个三元运算符只是为了检查空值)以及四个单独的减法运算符是不必要的复杂。 - Jed Schneider
从代码角度来看,这很有趣,但从可读性/维护性的角度来看,我不建议这样做。 - Larry K
+1 这绝对是最易读、最简单、最容易和最清晰的解决方案。令人惊讶的是,即使只使用简单的小学数学,您也可以实现简化!当然,真正正确的解决方案仍然是修复那个该死的漏洞,首先将所有这些nil泄漏到域模型中,但现在似乎很明显,OP根本不愿意这样做。 - Jörg W Mittag
这个解决方案对于大量或任意集合的扣除更具可扩展性,但我不同意Jörg关于其可读性/简单性的观点。不过,我完全同意Jörg关于在领域模型中摆脱nils的看法。 - Owen S.
显示剩余2条评论

5

如果对象的值没有在构造函数中提供,当对象创建时自动将其值初始化为0会更加简洁。否则,在需要这些值的对象中,您需要到处进行条件逻辑处理。您是否宁愿只是这样做呢?

amt = alt_inv - alt_tax - alt_freight - misc1_amt - misc2_amt 

在没有货运/税收等情况下,这些字段中可能有一些是“nil”。 - user229044
正如Jörg在下面所指出的那样,如果想要证明这种额外复杂性是足够重要的,则必须明确区分nil和0之间的差别。我持怀疑态度。 - Owen S.

1

如果您没有同名的本地变量,可以直接写alt_tax而不需要self.

此外,||运算符在第一个操作数不为nil时返回第一个操作数,否则返回第二个操作数,因此可以改为:

alt_tax ? alt_tax : 0

你可以写:

alt_tax || 0

很多Python程序员都有这个习惯。它让代码看起来非常凌乱! - AboutRuby

1

与Jed的解决方案略有不同,我认为它更加简洁,而且没有不必要的复杂性。

使用compactinjectreduce的最常见同义词)并不复杂,并且在Ruby程序员中广泛使用:

amt = [alt_tax, alt_freight, misc1_amt, misc2_amt].inject(alt_inv) do |result, attribute|
  result - (attribute || 0)
end

或者:

amt = alt_inv - [alt_freight, misc1_amt, misc2_amt].compact.inject{|sum, n| sum + n }

如果您对inject(&:+)语法不太熟悉,可以使用另一种替代方式。 如果您正在使用Rails,则可以使用sum方法替换inject,或者自己实现


0

对我来说看起来还不错,只有两个例外:

1)Ruby对语句结束做了一些假设。

由于

amt = self.alt_inv - (self.alt_tax ? self.alt_tax : 0)

本身是一个有效的语句,你需要在前一行保留减号或转义换行符。

2)Ruby假定“self”是所有者,除了左侧赋值。我建议:

amt = alt_inv - 
  (alt_tax     ? alt_tax     : 0) -
  (alt_freight ? alt_freight : 0) -
  (misc1_amt   ? misc1_amt   : 0) -
  (misc2_amt   ? misc2_amt   : 0)

有另一种写这个条件的方式。(alt_tax ? alt_tax : 0) - krunal shah
正如其他人所说,您还可以使用||运算符的“短路”行为。 - Larry K

0
amt = alt_inv - alt_tax.to_f - alt_freight.to_f - misc1_amt.to_f - misc2_amt.to_f
nil.to_f = 0.0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接