Are there any other options besides using the slice method in Javascript?

I am currently developing a calculator project that utilizes an array. My goal is to enable users to input multiple functions before obtaining the result, similar to the Casio fx-300ES Plus. At the moment, I am focusing on multiplication operations before progressing to other operators. I believe the most efficient approach is to identify the index of all 'x' characters using a for-loop, followed by two additional for-loops to examine the values on either side of the operator. Once another operator is encountered, the loop will terminate, allowing me to extract and store the relevant data adjacent to the 'x' symbol using slice().

However, I have encountered an issue when the numbers between operators are 1. Using slice() in such cases proves ineffective as there is no data between the specified indexes. Is there an alternative method to capture these numbers into an array?

Any insights or suggestions on this matter would be greatly valued.

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);
        }
    }

Answer №1

You have the option to create a function called tokenize that takes in your text input and generates a sequence 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}

Next, you can implement the parse function which processes a stream of tokens and generates an 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 }
}

Lastly, there is the eval function 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 a separate function called evalOp. This technique, known as mutual recursion, is highly effective for navigating 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}`)
  }
}

By incorporating tokenize, parse, and eval, you can calculate the final result -

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

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

This outcome is accurate when following the order of operations used in pocket calculators -

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

If you wish to evaluate using a different order of operations like PEMDAS, you would need to adjust the parse function to interpret the token stream differently.

Feel free to expand the code snippet below to verify the result in your browser -

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 }
}

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()
}

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

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}`)
  }
}

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Expanding the capabilities of AngularJS templates

When working with the Play! Framework, one way I can make my layout code more DRY is by following these steps: Inside main.html: <h1>This is main</h1> #{doLayout /} <div id="footer">Footer content</div> In home.html: #{ext ...

Enhance the appearance of your angular chosen container with personalized classes

LINK : Click here to view the code HTML <!DOCTYPE html> <html ng-app="plunker"> <head> <meta charset="utf-8" /> <title>AngularJS Plunker</title> <link data-require="chosen@*" data-semver="1.0.0" rel=" ...

Obtain the name of the object method from inside the method itself

Imagine having an object like this: var app = {} inside which there is a method: app = { initialize: function () { } } Is it possible to retrieve the name of the method 'initialize' from within the initialize() function without explicit ...

The React application is experiencing difficulties in receiving the response data (JSON) from the Express server, despite the fact that

When making POST or GET requests to our Express server, served through PM2 on EC2, Postman receives the complete response with JSON data. However, our front end React app (both locally and deployed via CF) only gets the response status code and message. Th ...

What is the appropriate way to retrieve an array that has been stored in the this.state property?

https://i.stack.imgur.com/y9huN.jpgAs a newcomer to react, I have been exploring the react documentation on making Ajax calls. While the docs make it seem simple to retrieve JSON information and set it to a state variable, I've encountered some challe ...

How can I retrieve my array state in a different router page using VUEJS and VUEX?

I have created a page with two routes - one for the home page and another for the configuration where users can decide what content should be displayed on that container. In the configuration panel, I was able to retrieve input values and stored them in my ...

Adjusting the rotation transform by deleting and reapplying canvas is causing the chart to not display data after redrawing

I am facing a challenge with my previous issue and I am exploring different solutions. One approach I am considering is to remove the canvas element completely and then re-add it, effectively resetting all rotations on the canvas. Although this method alm ...

How can you reposition a component within the dom using Angular?

Just started learning Angular, so I'm hoping this question is simple :) Without getting too specific with code, I could use some guidance to point me in the right direction. I'm currently developing a small shopping list application. The idea i ...

Storing the locations of draggable items with personalized user-created material

If I needed to store dynamically created content in a specific position within a container, what would be the best approach? For instance, if a user enters a YouTube URL into an input box and it generates an embedded video in a box container upon hitting ...

Using JavaScript to retrieve the server file's date stamp

Is it possible to use an ajax request in JavaScript or jQuery to grab the date a file was last modified (or created) on a static page that does not utilize server-side scripting? ...

Leveraging Vue.js plugin within a single file component

I am looking to utilize the vue-chartkick plugin in my Vue application, but I want to register it within my single-file components instead of globally. Is there a way to achieve this same functionality without using Vue.use(VueChartkick, { Chartkick })? ...

Ajax request results in a 400 error code

Here is the structure of my Ajax call: function Submit() { var objectData = { email: $("#email").val(), firstName: $("#firstName").val(), lastName: $("#lastName").val(), loginMode: $("#login ...

Ways to Update the Name of a Class Depending on the Elements in an Array

I am new to JavaScript, so please explain in simple terms. In the code snippet below, I need to change the class name of specific array elements - namely orange, yellow, and violet to use the class btn btn-outline-dark. Can this be achieved without adding ...

What could be causing me to receive an undefined output when trying to access an array stored within an object

let newData = await tripModel.find( { tripId: ID }, {salesOrder:1, no: "$deliveryDetails.invoiceNo", _id: 0 } ); let nullInvoices = []; console.log("vvvvvvv", newData[0].salesOrder); for (let i = 0; i < newData[0].no.length; i++) ...

Sequential visualization of data using R plots

I need to create time series, acf, and pacf plots for each row in an array of NCT. It is straightforward to do this for a single row: par(mfrow=c(3,1)) x <- x_whole[N,C,(1:T)] plot(x, t='l') abline(h=mean(x), col='red') acf(x, lag. ...

Unexpected TypeScript issue: Unable to access the 'flags' property of an undefined entity

Upon creating a new project and running the serve command, I encountered the following error: ERROR in TypeError: Cannot read property 'flags' of undefined Node version: 12.14 NPM version: 6.13 Contents of package.json: { "name": "angular-t ...

Managing and Streaming Music in a Rails Application

Currently, I am storing mp3s using paperclip and they only play back if I utilize Amazon S3. However, I am hesitant to use Amazon S3 because I am unsure how to secure the files. Now, I am reconsidering my approach as I need to secure the mp3s and provide ...

Sharing node_modules via Npm and ensuring the package.json is correctly mapped

I have a dilemma with two projects, one serving as a server and the other as a client. They share very similar dependencies, making it tedious to set up shared dependencies without manual file editing or installing everything twice. The issue is exacerbate ...

Is it necessary for the keys in separate loops to be unique among siblings?

Does the use of key in loops create separate branches, or do they still need to be unique for the same parent? Take a look at this example: // This is obviously an error: <div> <div key="gimme-a-break" /> <div key="gim ...

Updating a web page in Node.js with Express when new data is added to the database

I've managed to set up messaging on my website, but I want the recipient to see messages in real-time without needing to refresh the page. It would be neat if a notification or badge appeared for the user when they receive a new message. As a beginn ...