0

The problematic to resolve:

Given a string that contains a mathematical expression, I need a function on C# language that receives that string and returns its decimal result that respects the operators hierarchy. So for example:

CalculateExpression("10×2-5÷4"); should return 18.75.

Some considerations:

  • My initial approach is based on a stack method by using a Reverse Polish Notation (RPN).
  • I'm not taking into consideration parenthesis ( ) nor this caret: ^ because for my project case, the user will never be able to type those characters. So for operators, the only ones that would be available are : + - × ÷.
  • The function should recognize decimals dots, so for example CalculateExpression("15.4+5.5"); should return 20.9.

What I did:

While it works as I wanted, I'd like to receive feedback on the overall algorithm process, so I can enhance it or maybe there is something I didn't consider that someone would if it is seen or maybe there is already a library that does something done here.

Any tip works.

I tried to put comments on the most important things done and overall, what I'm doing in each section:

private static decimal CalculateInput(string input)
    {
        //the same input but splitted, so: "10+5" becomes ["10", "+", "5"]
        List<string> splittedInput = new List<string>();
        //stack for storing operators based on the RPN algorithm
        Stack<string> operatorStack = new Stack<string>();
        //the same splittedInput but formatted as PostFix, so: [10, +, 5] becomes ["10", "5", "+"]
        List<string> splittedPostFixExp = new List<string>();

        string strNumber = "";
        foreach (char theChar in input)
        {//looping through the string to append each operand and operator to the splittedInput List
            if (theChar != '+' && theChar != '-' && theChar != '×' && theChar != '÷')
            {
                strNumber += theChar;
            }
            else
            {
                splittedInput.Add(strNumber);
                splittedInput.Add(theChar.ToString());
                strNumber = string.Empty;
            }
        }
        splittedInput.Add(strNumber);

        //formatting the splittedInput to the PostFixed format
        foreach (string token in splittedInput)
        {
            if (token != "+" && token != "-" && token != "×" && token != "÷") //isOperand
            {
                splittedPostFixExp.Add(token);
            }
            else
            {
                if (operatorStack.Count != 0)
                {
                    if ((token == "×" || token == "÷") && (operatorStack.Peek() == "+" || operatorStack.Peek() == "-"))
                    {//upcoming token has greater precedence than top element on stack
                        operatorStack.Push(token);
                    }
                    else if ((token == "+" || token == "-") && (operatorStack.Peek() == "×" || operatorStack.Peek() == "÷"))
                    {//upcoming token has lower precedence than top element on stack
                        PopUntilLowerPrecedence(token);
                    }
                    else
                    {//upcoming token has the same precedence than top element on stack (basically the same as the previous condition)
                        PopUntilLowerPrecedence(token);
                    }
                }
                else
                {
                    operatorStack.Push(token);
                }
            }
        }

        while (operatorStack.Count != 0)
        {//Poping each operator in the stack to the end of the PostFixExpression
            splittedPostFixExp.Add(operatorStack.Pop());
        }

        void PopUntilLowerPrecedence(string token)
        {//function for poping the stack until the token has higher precedence than operatorStack.Peek()
            while (operatorStack.Count != 0)
            {
                if (((token == "×" || token == "÷") && (operatorStack.Peek() == "+" || operatorStack.Peek() == "-")))
                {//upcoming token has NOW greater precendence
                    break;
                }
                splittedPostFixExp.Add(operatorStack.Pop());
            }
            operatorStack.Push(token);
        }

        //calculating result by using the PostFixExpression
        for (int i = 0; i < splittedPostFixExp.Count; i++)
        {
            if (splittedPostFixExp[i] == "+" || splittedPostFixExp[i] == "-" || splittedPostFixExp[i] == "×" || splittedPostFixExp[i] == "÷")
            {
                decimal left = decimal.Parse(splittedPostFixExp[i - 2]);
                decimal right = decimal.Parse(splittedPostFixExp[i - 1]);
                decimal result = 0M;

                switch (splittedPostFixExp[i])
                {
                    case "+":
                        result = left + right;
                        break;
                    case "-":
                        result = left - right;
                        break;
                    case "×":
                        result = left * right;
                        break;
                    case "÷":
                        result = left / right;
                        break;
                }

                for (int j = i; j > i - 3; j--)
                {
                    splittedPostFixExp.RemoveAt(j);
                }

                splittedPostFixExp.Insert(i - 2, result.ToString());

                i = 0;
            }
        }

        return decimal.Parse(splittedPostFixExp[0]);
    }

Thanks in advance! Wishing you a nice day:)

Decker
  • 1
  • 3
  • if it works then it's a better fit on [codereview.se] – phuclv Sep 01 '21 at 01:12
  • @phuclv Oh, excuse me. Since I'm still pretty new on stackoverflow, i thought i could post this here. Should I delete it? – Decker Sep 01 '21 at 01:14
  • Code optimization questions are better fit on code-review as they can sometimes be opinionated. That platform better handles those types of discussions. Stack Overflow actually demotes questions that could raise opinions as there is no definitive right or wrong answer. – Andy Sep 01 '21 at 03:26
  • Whether to delete the question here is up to you. If you decide to post on Code Review deleting here is a right thing as SE generally does not encourage reposts on multiple sites. If you find out that CR version need to be different after carefully reading their help than I see no harm leaving this question on SO. Unlike many questions it clearly shows solid attempt to write code and is written well so I don't expect it to collect downvotes and maybe pick a vote or two at some point when one finds that question for their homework (an read https://meta.stackoverflow.com/questions/255583 early). – Alexei Levenkov Sep 01 '21 at 03:48

0 Answers0