A simple calculator in Python

A while back, I wrote a simple calculator in Ruby. A few minutes ago I ran into a similar question in Stackoverflow, and decided to implement the Python version:

def is_number(s):
    try:
        float(s)
        return True
    except ValueError:
        return False


def calc(expr):
    if is_number(expr):
        return float(expr)    
    arr = expr.split('+')
    if len(arr) > 1:
        return sum(map(calc, arr))
    arr = expr.split('-')
    if len(arr) > 1:
        return reduce(lambda x,y: x-y, map(calc, arr))
    arr = expr.split('*')
    if len(arr) > 1:
        return reduce(lambda x,y: x*y, map(calc, arr), 1)
    arr = expr.split('/')
    if len(arr) > 1:
        return reduce(lambda x,y: x/y, map(calc, arr))


print calc("3+4-2 *2/ 2")    # 5

Nice, isn’t it?

A simple calculator in Python

A simple calculator in Ruby

Today I ran (again) into the following question:

  • Write a function that doesn’t use eval that calculates input strings with operators +,-,*,/ eg. “5+5*6+4/2″ should output 37

The first time I ran into this question I designed a solution, in Java, which had a SimpleCalculator class, and enam Operation which supported the four basic arithmetic operations: +-*/ each of which had an apply method etc. Very object oriented.

When I read this question today, I figured that it would be a nice exercise to do in Ruby – a few minutes later the result spread, elegantly, over less than 20 lines of code (and I bet that a professional Rubiest can do it in less)!

def is_number? expr
  return false if expr.nil?
  expr = "#{expr}"              # we need this condition in case the expr is a number
  expr.match /^(\d+|\d+\.\d+)$/ # since match() is defined only for strings
end

def calc(expr)  
  return expr.to_i if is_number? expr
  expr.gsub!(" ","") # clean the string from whitespaces
  # pay attention to the order: + and - should come before * and /
  # can you figure out why ?
  arr = expr.split /\+/
  return arr.inject(0){|x,y| calc(x) + calc(y) } if arr.size > 1
  arr = expr.split /\-/  
  return arr.inject(0){|x,y| calc(x) - calc(y) } if arr.size > 1
  arr = expr.split /\*/
  return arr.inject(1){|x,y| calc(x) * calc(y) } if arr.size > 1
  arr = expr.split /\//
  return arr.inject   {|x,y| calc(x) / calc(y) } if arr.size > 1
end

puts calc("5+5* 6+4/2.0")
#output 37

Do you have a better/shorter/more elegant solution ?
Please post it in the comments section!

A simple calculator in Ruby