2

I've set myself the challenge of a RPN calculator. I have a list with the numbers used (in order) and another list with the operators used (in order, as chars). How can I create a function that will take the [0] from list1, take [0] from list2, then [1] from list1, then [1] from list2... but when taking a value from list2 as a char, converts it to an actual operator that can be used in calculations? - Thanks

static int cal()
{
    string[] store = input.Split(' ');
    List<int> num = new List<int>();
    List<char> op = new List<char>();

    foreach (string i in store)
    {
        if (Convert.ToInt32(i) / Convert.ToInt32(i) == 1)
        {
            num.Add(Convert.ToInt32(i));
        }
        else
        {
            op.Add(Convert.ToChar(i));
        }
    }            
}
Fayyaz Naqvi
  • 695
  • 7
  • 19
user3355678
  • 23
  • 1
  • 3
  • 2
    You do realize that an RPN processor needs a stack right? Your whole approach is invalid with the 2 separate lists, and will never succeed in RPN expressions more complex than 2 operands. – Niels Keurentjes Dec 02 '15 at 10:53

3 Answers3

3

First up, this kind of calculator probably suits Stack as the data store.

var theStack = new Stack<decimal>();

Then, if you want to start simple, create a delegate to represent binary operations (eg, operations on the top 2 numbers on the stack)

delegate decimal BinaryOperation(decimal a, decimal b);

You can create methods to implement this;

public decimal AddFn(decimal a, decimal b) 
{
    return a+b;
}

then create a dictionary to map between operator names and operator function;

var map = new Dictionary<string, BinaryOperation>();
map.Add("+", AddFn);

Last, use the map when running the program;

foreach(var i in store)
{
    decimal number;
    BinaryOperation op;

    if (decimal.TryParse(i, out number))
    {
        // we've found a number
        theStack.Push(number);
    } 
    else if (map.TryGetValue(i, out op))
    {
        // we've found a known operator;
        var a = theStack.Pop();
        var b = theStack.Pop();
        var result = op(a,b);
        theStack.Push(result);
    }
    else
    {
        throw new Exception("syntax error");
    }
}

So you can register more operators with the map variable without having to change the core logic of pushing, popping, and operating with values on the stack.

Steve Cooper
  • 20,542
  • 15
  • 71
  • 88
0

Your approach can never work as an RPN calculator depends on having a stack based processing. If you implement that part right the rest will solve itself. The pseudocode for a simple RPN calculator would be:

foreach(item in expression)
{
  if(isNumber(item))
    stack.push(item.toNumber());
  else if(item == '+')
    stack.push(stack.pop() + stack.pop());
  else if(item == '-')
    stack.push(stack.pop() - stack.pop());
  else
    throw Exception("Unknown operator: " + item);
}
if(stack.size != 1)
  throw Exception("Expression was invalid");
print("Result is " + stack.pop());

If you implement it like this instead of the 2 separate lists the rest will follow.

Niels Keurentjes
  • 41,402
  • 9
  • 98
  • 136
0

I guess, your method cold look like this:

static int cal()

    {
        string[] store = input.Split(' ');
        var res = 0;
        int value;

        var mapOp = new Dictionary<string, Func<List<int>, int>>();
        mapOp.Add("+", l => l.Aggregate(0, (x, y) => x + y));
        mapOp.Add("-", l => l.Skip(1).Aggregate(l[0], (x, y) => x - y));
        var process = new Action<string,List<int>>((o, l) =>
        {
            var operation = mapOp[o];
            var result = operation(l);
            l.Clear();
            l.Add(result);
        });
        var numbers = new List<int>();
        foreach (var i in store)
        {
            if (int.TryParse(i, out value))
                numbers.Add(value);
            else
                process(i, numbers);
        }
        return numbers.First();
    }
Mitklantekutli
  • 410
  • 1
  • 3
  • 16