Essentially I have a evaluate method that takes something like
['+','2','3']
which would evaluate to 5.
It's currently set up like so,
def evaluate(exp)
f = exp[0]
if f == '+' then
return exp[1].to_i + exp[2].to_i
elsif f == '-' then
return exp[1].to_i - exp[2].to_i
elsif f == '*' then
return exp[1].to_i * exp[2].to_i
elsif f == '/' then
return exp[1].to_i / exp[2].to_i
end
end
This works fine, but there has to be a better way to do this without a giant if. Is there a way for me to convert the symbol and use it? How do typically lisp interpreters handle this?
Ruby's all about dynamic programming. In fact this makes your code ridiculously easy:
def evaluate(exp)
exp[1].to_i.send(exp[0], exp[2].to_i)
end
It'd be even easier if those tokens were converted on the way in:
exp.map! do |token|
case (token)
when /\A\-?\d+\z/
token.to_i
else
token
end
end
Then you get this:
def evaluate(exp)
exp[1].send(exp[0], exp[2])
end
Now this presumes you're only supplying valid operations, that you're not doing anything absurd, but for trivial cases it works quite well.
If you've converted everything and you're looking to make this more extensible:
def evaluate(exp)
op, *args = exp
args.reduce(&op.to_sym)
end
Then you can do this on arbitrary lists:
evaluate([ '+', 2, 1, 3, 4 ])
def evaluate(*args)
operation, *numbers = args
numbers.map!(&:to_i)
numbers.first.public_send(operation, numbers.last)
end
If you expect more, than two numbers to be used:
def evaluate(*args)
operation, *numbers = args
numbers.map!(&:to_i).inject(&operation.to_sym)
end
evaluate('+','2','3', 4, 5, 6)
#=> 20
You can add an initial value if you need to make sure to always return a Numeric from the method (make sure to select any non-zero number, if operation is division or multiplication):
def evaluate(*args)
operation, *numbers = args
initial_value = %w(/ *).include?(operation) ? 1 : 0
numbers.map!(&:to_i).inject(initial_value, &operation.to_sym) #<==== note 0
end
evaluate '+'
#=> 0
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With