Лучший способ написать этот расчет в Ruby? - PullRequest
3 голосов
/ 25 августа 2010

Как лучше написать этот расчет в 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 голосов
/ 25 августа 2010

В Ruby, если что-то не равно nil, он возвращает true в логическом выражении и его значение в вычислении.

Я не очень хорошо объясняю, но вы можете сделать что-то вроде этого:

amt = alt_inv - 
  (alt_tax     || 0) -
  (alt_freight || 0) -
  (misc1_amt   || 0) -
  (misc2_amt   || 0)

Это более краткий способ сделать троичный, который вы изначально использовали.


Edit:

На самом деле мне больше нравится ответ Джеда Шнайдера, чем мой собственный. Я не буду копировать его здесь, так как его ответ заслуживает одобрения за его элегантность.

6 голосов
/ 26 августа 2010

Поскольку amt - это разница между суммой всех атрибутов и alt_inv, вы можете суммировать вычеты и затем вычесть из alt_inv. reduce предлагает чистый способ сделать это. compact удаляет все значения nil перед выполнением сокращения.

Конечно, атрибуты в этом случае могут быть расширены до любых ваших потребностей, даже если они создаются динамически из данных, и в реальной жизни я бы не стал использовать атрибуты переменных, очевидно.

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

уменьшить: http://apidock.com/ruby/Enumerable/reduce

компактный: http://apidock.com/ruby/Array/compact

5 голосов
/ 25 августа 2010

Может быть чище, если бы вы могли автоматически инициализировать значения вашего объекта равными 0 при создании объекта, если эти значения не были предоставлены в конструкторе.В противном случае вам нужно выполнять условную логику такого рода везде в ваших объектах, где эти значения необходимы.Не лучше ли просто сделать это?

amt = alt_inv - alt_tax - alt_freight - misc1_amt - misc2_amt 
1 голос
/ 26 августа 2010

Небольшое отклонение от решения Джеда, которое не является излишне сложным, но более кратким ИМХО.

Использование compact и inject (самый распространенный синоним reduce) не сложныи тщательно используется программистами на 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 или реализовать его самостоятельно .

1 голос
/ 26 августа 2010

Если у вас нет локальной переменной с тем же именем, вместо self.alt_tax вы можете написать просто alt_tax без self.

Также оператор || возвращает первый операнд, когдане ноль, иначе возвращается второе, поэтому вместо:

alt_tax ? alt_tax : 0

вы можете написать:

alt_tax || 0
0 голосов
/ 26 августа 2010
amt = alt_inv - alt_tax.to_f - alt_freight.to_f - misc1_amt.to_f - misc2_amt.to_f
nil.to_f = 0.0
0 голосов
/ 25 августа 2010

Выглядит нормально для меня с двумя исключениями:

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...