Могу ли я избежать if-elsif-else в этой функции ruby? - PullRequest
1 голос
/ 22 декабря 2011

У меня есть три значения (foo, bar, bad) и в зависимости от того, какое из них я передаю в функцию, я хочу использовать два других.

Например, вызов self.method(foo) приведет к чему-то подобному с foo неопределенным.

def method
  self.foo = 180 - self.bar - self.bad
end

Я могу сделать это с помощью простой установки if-elsif-else, ноесть лучший (более идиоматический) способ?

Обновление для ясности:

Вот как может выглядеть одно предложение в производстве:

def solve_angles(missing)
  angles = 180 - [ A, B, C ].reject { |e| e == missing }.inject(:+)
end

вызывается через @triangle.solve_angles(self.C) или даже '@ triangle.solve_angles ("C").

Ответы [ 4 ]

0 голосов
/ 22 декабря 2011

Вот решение, которое я придумал:

def solve_angles(missing)
      holder = [:A, :B, :C]
      holder.delete(missing)
      angle = 180 - (self.send(holder[0]) + self.send(holder[1]))
end

Это плохое решение? Почему?

Или это чище / лучше?

def solve_angles(missing)
  holder = [:A, :B, :C] - [missing]
  angle = 180 - send(holder[0]) - send(holder[1])
end

Или:

def solve_angles(missing)
  angles = [:A, :B, :C] - [missing]
  angles.inject(180) { |memo, a| memo - send(a) }
end
0 голосов
/ 22 декабря 2011

Попробуйте что-нибудь вроде этого:

def method(arg)
  [ bar, bad, foo ].reject { |e| e == arg }.inject(:+)
end

Обратите внимание, что для приемника self это не так, это неявно.

0 голосов
/ 22 декабря 2011

Вам не нужно указывать какой угол вы решаете; это подразумевается в определении проблемы. Если вы начнете с чего-то подобного (что-то похожее на обработку ошибок, вылетает):

class Triangle
  def initialize h
    h.keys.each { |key| instance_variable_set "@#{key}".to_sym, h[key] }
  end

  def to_s
    "a=#{@a}, b=#{@b}, c=#{@c}"
  end

  def solve
    angle = instance_variables.inject(180) { |v, a| v -= instance_variable_get(a) }
    [:@a, :@b, :@c].each {|s| instance_variable_set(s, angle) unless instance_variable_defined? s }
    self
  end
end

Тогда:

pry(main)> t = Triangle.new :a => 20, :c => 30
=> a=20, b=, c=30
pry(main)> t.solve
=> a=20, b=130, c=30
pry(main)> 

При необходимости вы также можете возвратить / указать, какой угол был фактически решен.

Это на самом деле не избегает заявления if, которое было вашим конкретным вопросом. Это устраняет необходимость в явном изложении каждого из них, которое я принял за цель вопроса.

Если вам действительно нужно «решить за», вы можете добавить:

def solve_for sym
  solve
  instance_variable_get("@#{sym}".to_sym)
end

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

> t = Triangle.new :a => 20, :c => 30
=> a=20, b=, c=30
> t.solve_for :b
=> 130
> t
=> a=20, b=130, c=30
> t = Triangle.new :a => 20, :c => 30
=> a=20, b=, c=30
> t.solve_for :a
=> 20
> t
=> a=20, b=130, c=30
0 голосов
/ 22 декабря 2011

Если это просто простое сложение, умножение и т. Д., То будет достаточно следующего, но ничего более сложного не гарантируется.

def method(input)
  self.foo + self.bar + self.bad - input
end

В качестве альтернативы, вы можете поместить их все в массив и удалить одинВы предоставили.

def method(input)
  [self.foo, self.bar, self.bad].reject { |e| e==input }.inject { ... }
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...