wasnt nate

Interview Question: Create a Calculator

For a recent interview question I was asked to write a method that would evaluate a string such as “-2+5*4/2+1″ into the value 9.

My solution was done in 3 parts; first tokenize the string so each block of digits or operator can be addressed at the same time.

public static float Evaluate(string expression)
{
  if (string.IsNullOrEmpty(expression))
    throw new ArgumentNullException("expression");

  //
  //  First tokenize the string
  var tokens = new List<string>();
  var token = string.Empty;
  for (var i = 0; i < expression.Length; i++)
  {
    if (IsOperator(expression[i]))
    {
      //
      //  If the expression starts with a negative number
      if (expression[i] == '-' && tokens.Count == 0 
              && string.IsNullOrEmpty(token))
      {
        token = "-";
        continue;
      }

      if (!string.IsNullOrEmpty(token))
      {
        tokens.Add(token);
        token = string.Empty;
      }

      tokens.Add(expression[i].ToString());

      //
      //  Handle case of negative numbers such as: 2*-3
      if (expression[i + 1] == '-')
      {
        token = "-";
        ++i;
        continue;
      }
    }
    else if (char.IsDigit(expression[i]))
    {
      token += expression[i];
    }
    else if (char.IsWhiteSpace(expression[i]))
    {
      if (!string.IsNullOrEmpty(token))
      {
        tokens.Add(token);
        token = string.Empty;
      }
      continue;
    }
    else
       throw new InvalidOperationException
           ("Invalid char:" + expression[i]);
  }

  if (!string.IsNullOrEmpty(token))
    tokens.Add(token);

Then process all the multiply and divide operations

 
 //
 //  Process any multiple/divide requests
 for (var i = 0; i < tokens.Count; )
 {
   var currentToken = tokens[i];
   if (currentToken == "*" || currentToken == "/")
   {
     var left = tokens[i - 1];
     var right = tokens[i + 1];
     var value = string.Empty;

     if (currentToken == "*")
       value = Convert.ToString
           (float.Parse(left) * float.Parse(right));
     else
       value = Convert.ToString
           (float.Parse(left) / float.Parse(right));

     //
     //  Update the left value and remove the processed operators
     tokens[i - 1] = value;
     tokens.RemoveAt(i + 1);
     tokens.RemoveAt(i);
   }
   else
   i++;
 }

Finally process any add or subtract operations

 //
 //  Process any add/subtract requests
 float finalValue = float.Parse(tokens[0]);
 for (var i = 1; i < tokens.Count; i++)
 {
   var currentToken = tokens[i];
   if (currentToken == "+")
   {
     finalValue += float.Parse(tokens[++i]);
   }
   else
   {
     finalValue -= float.Parse(tokens[++i]);
   }
  }

  //
  //  Return the final value
  return finalValue;
}

For completeness-

static bool IsOperator(char ch)
{
  return new char[] { '+', '-', '/', '*' }.Contains(ch);
}

Leave a Reply