Skip to content

Instantly share code, notes, and snippets.

@FrancoB411
Last active June 8, 2018 16:59
Show Gist options
  • Save FrancoB411/4c4dccc888ce674f72a0202e17c67e49 to your computer and use it in GitHub Desktop.
Save FrancoB411/4c4dccc888ce674f72a0202e17c67e49 to your computer and use it in GitHub Desktop.
Refactored to have a cleaner API, so users can calculate without explicitly newing up the class.
class Calculator
ORDERED_OPERATIONS = %W(* / + -) # maintainable, add new operations easily
# no need to new up if you don't want to.
def self.calculate(input)
new.calculate(input)
end
# There is a pathological case where unknown operators are entered.
# So input validations would be a good idea in a production setting.
def calculate(input)
input = input.split(" ") # doesn't mutate the original input, may have tradeoffs in terms of memory for very long inputs
while input.length > 1 do # imperative, so 71% faster than recursive according to profiler
ORDERED_OPERATIONS.each do | op | # runs through each operation til it exhausts them in order
i = input.find_index(op)
# N**2 worst case, but each iteration will be N-2 for each found operation, so closer to N*(N/2) avg.
# Since N = 4 in the ORDERED_OPERATIONS array it's more like constant.
if i
prev = input[i-1].to_f # seemed more readable not to dry these up.
nex = input[i+1].to_f
result = operate(prev, op, nex) # now it accepts whatever operations you want, even custom methods
input = update_input_with_result(input, result, i) # naming is hard
end
end
end
input.first
end
private
def operate(prev, op, nex)
prev.send(op, nex)
end
def update_input_with_result(input, result, i)
input.slice!((i-1)..(i+1)) #extract evaluated items
input[i-1] = result #insert result into input
input
end
end
input = '7 - 2 + 3 / 4 * 5'
expected = (7 - (2 + (3 / (4 * 5.to_f))))
actual = Calculator.calculate(input)
puts actual
puts (expected == actual)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment