0

Working a evaluator for Polish Notation and I was adding a way to distinguish if the string I got was a number or not using the isNaN function. This works fine, until you add + + to the string.

function cuttingString(list) {
    let adjustArr = list.split(' ')
    let topper = []
    for (let i = 0; i < adjustArr.length; i++) {
        if (!isNaN(adjustArr[i])) {
            topper.push(adjustArr[i])
            console.log(topper)
        } else {
            let j = topper.pop()
            let k = topper.pop()

            if (adjustArr[i] === '+') {
                topper.push(parseInt(j) + parseInt(k))
            }
        }
    }
}

console.log(cuttingString('* 1 2 30 +'))

works as expected with '* 1 2 30 +' it outputs [1,2,30] However, when I start moving around the operators, is when I get a NaN in the beginning of my arrays [NaN, 1,2,30] which is incredibly frustrating. Any ideas on how to fix this problem or other work arounds?

trincot
  • 317,000
  • 35
  • 244
  • 286
4156
  • 380
  • 4
  • 17
  • 2
    Please provide a [mcve] of your problem. The code you've shown isn't enough - `adjustArr` seems like an array, however you claim to be passing a string. We have no idea how that string gets converted into the array. – VLAZ Jan 30 '21 at 08:19
  • @vlaz added sir! – 4156 Jan 30 '21 at 08:21
  • 1
    You are missing a `return topper` for the code to actually work as example. But I'm not sure I understand your problem, can you give an input string that shows it, and what you expected instead? You will get `NaN` if you are underflowing your buffer, so for example just the string `+` will result in `NaN` because it tries to pop two numbers and add them, but there are no numbers in `topper` yet. I noticed you have `*` in your example, yet you don't implement the `*` operator so far... – CherryDT Jan 30 '21 at 12:48
  • 2
    You have provided code that gives the desired output. You write *"when I start moving around the operators"*... but don't leave it to us to *guess* in which scenario it goes wrong. Please provide the code where it outputs NaN. Be aware that the first occurrence of a binary operator (like `+`) cannot occur before you have had two numbers, otherwise the binary operator has not enough arguments, and you would get a NaN (because one of the `pop` calls then returns `undefined`). So in that respect it makes no sense that the input starts with `*`. NB: I turned your code into a runnable snippet. – trincot Jan 30 '21 at 15:29
  • @trincot in Polish notation, the binary operator comes before its operands. You're thinking of _reverse_ Polish notation. – Patrick Roberts Jan 30 '21 at 15:35
  • 1
    Yes I am, but that is exactly what the OP is doing in their code, so I think they have implemented the reverse and wrongly labelled it Polish instead of reverse Polish. – trincot Jan 30 '21 at 15:36
  • Apologies, I did not realize that was how you'd interpreted the question. Given the input string they're working with as an example, and the fact they're calling it Polish notation, I had just believed they had accidentally implemented reverse Polish notation when they're trying to implement normal Polish. – Patrick Roberts Jan 30 '21 at 15:40
  • `* 1 2 30 +` is neither [tag:prefix-notation] nor [tag:postfix-notation]. It is some bizarre mixture of both. Please clarify your question and tags. – user207421 Feb 27 '22 at 04:09

1 Answers1

1

Your code seems to implement reverse Polish notation, and so you cannot expect it to work correctly if you don't provide arguments before any of the binary operators. So you cannot randomly move the + around in the expression. A binary operator can only occur if there are at least two numbers available on the stack. If not, the call to pop will return undefined and parseInt(undefined) is NaN. Although you did not implement multiplication yet, it is problematic that the * occurs at a time when the stack is still empty.

It would make sense to have your function return the result, as your console.log will currently only output undefined and so you don't actually see the result of the calculation.

If indeed, your idea was to implement an evaluator for reverse Polish notation, then here is what I would adapt to your code:

function cuttingString(list) {
    // Allow multiple spaces, also at start/end:
    let adjustArr = list.match(/\S+/g); 
    let topper = [];
    // Use for..of loop
    for (let token of adjustArr) {
        if (!isNaN(token)) {
            // Why not convert to number here...
            //   and allow decimals. Use unary plus
            topper.push(+token);
        } else if (topper.length < 2) {
            // Show error message when not enough arguments
            throw "not enough arguments for " + token;
        } else {
            let j = topper.pop();
            let k = topper.pop();
            if (token === '+') {
                topper.push(j + k);
            }
        }
    }
    // Verify that the evaluation is complete
    if (topper.length !== 1) {
        throw "Evaluation did not yield one value but " + topper.length;
    }
    // Return the value 
    return topper.pop();
}

console.log(cuttingString('1 2 30 + +')); // 33
console.log(cuttingString('1 2 + 30 +')); // 33

The two examples in this code are the only places where you can move the + operator to. For instance, neither of the following is valid:

console.log(cuttingString('1 2 + + 30'));
console.log(cuttingString('1 + 2 30 +'));

In either case, there arises a situation where the stack does not have enough arguments for a binary operator. The code above will provide a specific error message for that.

trincot
  • 317,000
  • 35
  • 244
  • 286