Home > Software engineering >  Is there an alternative to slice in Javascript? [closed]
Is there an alternative to slice in Javascript? [closed]

Time:09-17

I am working on a calculator project using an array. I wanted to allow the user to write multiple functions before finding the answer, similar to a Casio fx-300ES Plus. Right now I am working on multiplication before moving to other operators. To do this I thought the best way is to find the index at which all 'x' are located using a for-loop, then run two other for-loops, one looking at the left of the operator, the other looking at the right of it. Once it finds another operator, it will break. I could then store the information next to the 'x' using slice().

The problem I have run in to is when the numbers between operators is 1. If I use slice() it does not work as there is no information between the indexes. Is there another way to store these numbers into an array?

Any information on this is much appreciated.

var array = ['7', '3', ' ', '6', 'x', '8', ' ', '5', '4', 'x', '2'];

    //for loop checking for 'x' symbols
    for (var i = 0; i < array.length; i  ){
        console.log("i "   array[i]);
        //if there is an 'x'
        if (array[i] == 'x') {
            console.log('index is at '   i);
            //create an array to eventually store the values
            var newArray = new Array();
                //checks for the index where j is NaN on the LEFT side
                for (j = i - 1; j > 0; --j){
                    if (isNaN(array[j])){
                        console.log('j is '   j);
                        break;
                    }
                }  
                //checks for the index where e is NaN on the RIGHT side
                for (e = i   1; e < array.length; e  )
                {
                    if (isNaN(array[e])){
                        console.log('e is at '   e);
                        break;
                    } else if (e == array.length - 1) {
                        console.log('e is at array length of '   e);
                        break;
                    }
                }
              //add the numbers between j and i to newArray
              newArray = array.slice(j   1, i);
                        console.log(newArray);
              //add the numbers between i and e to newArray
              newArray = array.slice(i   1, e);
                        console.log(newArray);  
              console.log("array of slice is "   newArray);
        }
    }

CodePudding user response:

You could write tokenize which consumes your text input and produces a stream of tokens -

const input = 
  [ '7', '3', ' ', '6', 'x', '8', ' ', '5', '4', 'x', '2' ]
  
function* tokenize (es) {
  let r = 0, n
  for (const e of es) {
    switch (e) {
      case " ":
      case "x":
        yield { number: r }
        yield { operation: e }
        r = 0
        break
      default:
        n = Number.parseInt(e, 10)
        if (Number.isNaN(n))
          throw Error(`unexpected input: ${e}`)
        else
          r = r * 10   n
        break
    }
  }
  if (r > 0) yield { number: r }
}
          
for (const t of tokenize(input))
  console.log(t)

{"number":73}
{"operation":" "}
{"number":6}
{"operation":"x"}
{"number":8}
{"operation":" "}
{"number":54}
{"operation":"x"}
{"number":2}

Followed by parse which consumes a stream of tokens and produces a abstract syntax tree -

function parse (ts) {
  let s = e => e
  for (const t of ts) {
    if (t?.number) {
      let r = s(t)
      s = _ => r
    }
    else if (t?.operation) {
      let left = s()
      s = right => ({ operation: t.operation, left, right })
    }
    else {
      throw Error(`unexpected token: ${JSON.stringify(t)}`)
    }
  }
  return s()
}
console.log(parse(tokenize(input)))
{
  operation: "x",
  left: {
    operation: " ",
    left: {
      operation: "x",
      left: {
        operation: " ",
        left: { number: 73 },
        right: { number: 6 }
      },
      right: { number: 8 }
    },
    right: { number: 54 }
  },
  right: { number: 2 }
}

Finally eval which evaluates the syntax tree as a program -

function eval (e) {
  if (e?.number)
    return e.number
  else if (e?.operation)
    return evalOp(e)
  else
    throw Error(`unexpected expression: ${JSON.stringify(e)}`)
}

We simplify eval by writing evalOp separately. This technique is known as mutual recursion and is super effective for traversing tree-like structures -

function evalOp (e) {
  switch (e?.operation) {
    case " ": return eval(e.left)   eval(e.right)
    case "x": return eval(e.left) * eval(e.right)
    default: throw Error(`unexpected operation: ${e.operation}`)
  }
}

Bring tokenize, parse, and eval together to compute the result -

const input = 
  [ '7', '3', ' ', '6', 'x', '8', ' ', '5', '4', 'x', '2' ]

console.log(eval(parse(tokenize(input))))
1372

This is correct when evaluated using pocket calculator order of operations -

73 
...   6 = 79
... * 8 = 632
...   54 = 686
... * 2 = 1372

If you wanted to evaluate using a different order of operations, ie PEMDAS, you would have to rewrite parse to interpret the stream of tokens as a different program.

Expand the snippet below to verify the result in your browser -

  • Related