A guide on breaking down complex mathematical expressions with arrays using javascript

I am looking to store various mathematical expressions that involve basic operations such as addition, subtraction, multiplication, division, exponents, square roots, grouping, etc., along with unique placeholders in the form of a string.

const json = {
  “formula”: “{{a45bc2a1-ed82-4ccd-a455-f7959e875aad}}+({{f6c2ef2b-a4fa-4cfb-b62d-d0d7c3e266d9}}*{{335563ad-a715-47b9-8e54-2b8553768168}})”
}

The placeholders correspond to arrays like so:

const map = {
  “a45bc2a1-ed82-4ccd-a455-f7959e875aad”: [1, 2, 3, 4, 5],
  “f6c2ef2b-a4fa-4cfb-b62d-d0d7c3e266d9”: [10, 20, 30, 40, 50],
  “335563ad-a715-47b9-8e54-2b8553768168”: [1, 2, 3, 4, 5]
}

Is there a way to accomplish this? The eval() function is not suitable for vector operations and I am uncertain about how to parse arbitrary formulas for element-wise calculations.

The expected output should be:

[11, 42, 93, 164, 255]

Answer №1

As you embark on the journey of creating your own programming language, it becomes essential to have a compiler (which translates string expressions into an Abstract Syntax Tree) and a runtime (responsible for evaluating the AST with given inputs and predefined bindings). Below is a snippet of code to kickstart your project. It has limited support for grammar

expression = term | term op expression
and lacks error handling:

// "compiler"

function parse(str) {
    return expr([...str])
}

function expr(chars) {
    let node = term(chars)
    if (chars.length)
        node = {
            op: chars.shift(),
            left: node,
            right: expr(chars)
        }
    return node
}

function term(chars) {
    let str = ''
    while (chars.length && chars[0].match(/\w/))
        str += chars.shift()
    return {value: str}
}

// "runtime"

ops = {
    '+': (a, b) => a + b,
    '-': (a, b) => a - b,
}

function evaluate(node, bindings) {
    if (node.value)
        return bindings[node.value]
    return eval_op(
        node.op,
        evaluate(node.left, bindings),
        evaluate(node.right, bindings))
}

function eval_op(op, left, right) {
    let fn = ops[op]
    return left.map((_, i) => fn(left[i], right[i]))
}

// demo

input = 'abc+def+xyz'
bindings = {
    'abc': [1, 2, 3],
    'def': [4, 5, 6],
    'xyz': [7, 8, 9],
}

ast = parse(input)
console.log('AST', ast)
res = evaluate(ast, bindings)
console.log('RESULT', res)

Transforming this prototype into fully functional code requires further effort. I recommend delving deeper into formal grammars, parsers, and parser generators to enhance your understanding.

Answer №2

Iterate through the array indices, and substitute the placeholders with the current index in the corresponding part of map. Next, execute the eval() function.

let length = Object.values(json.formula)[0].length;
for (let j = 0; j < len; j++) {
    let formula = json.formula.replace(/{{([-\w]+)}}/g, (match, placeholder) => map[placeholder][j];
    console.log(eval(formula));
}

Answer №3

After experimenting for some time today, I managed to develop a functioning version that eliminates the need for defining a formal AST. This implementation solely relies on eval() to create an arrow function responsible for calculating each index of the output based on input lists and an increasing input index.

'use strict';
const json={
    formula: '{{a45bc2a1-ed82-4ccd-a455-f7959e875aad}}+({{f6c2ef2b-a4fa-4cfb-b62d-d0d7c3e266d9}}*{{335563ad-a715-47b9-8e54-2b8553768168}})'
}

const map = {
    'a45bc2a1-ed82-4ccd-a455-f7959e875aad': [1, 2, 3, 4, 5],
    'f6c2ef2b-a4fa-4cfb-b62d-d0d7c3e266d9': [10, 20, 30, 40, 50],
    '335563ad-a715-47b9-8e54-2b8553768168': [1, 2, 3, 4, 5]
}

function parseFormula (formula) {
    const template = /{{([^}]*)}}/;
    const idList = [];
    for (let i = 0; template.test(formula); i++) {
        idList.push(formula.match(template)[0].replace(/[{}]/g, ''));
        formula = formula.replace(template, `input[${i}][i]`);
    }
    return {idList, formula};
}

function calculateFormula(map, parsed) {
    const input = [];
    const result = [];
    const lambda = eval(`(input, i) => ${parsed.formula}`)
    parsed.idList.forEach(id => input.push(map[id]));
    for (let i = 0; i < input[0].length; i++) {
        result.push(lambda(input, i));
    }
    return result;
}

const parsed = parseFormula(json.formula);
console.log(parsed);
console.log(calculateFormula(map, parsed));

Output:

{
  idList: [
    'a45bc2a1-ed82-4ccd-a455-f7959e875aad',       
    'f6c2ef2b-a4fa-4cfb-b62d-d0d7c3e266d9',       
    '335563ad-a715-47b9-8e54-2b8553768168'        
  ],
  formula: 'input[0][i]+(input[1][i]*input[2][i])'
}
[ 11, 42, 93, 164, 255 ]

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

Is it possible to edit the JSON file served by the API in NextJS during runtime and have the API serve the updated file?

I apologize for the wording of my question. My main struggle lies in not being able to articulate it properly, as I have searched extensively online without finding a solution. In my usage of api routes in Next.js, I am seeking to serve a data.json file. ...

What is the best way to configure Jenkins to exclude or include specific component.spec.ts files from being executed during the build

Currently, I am facing an issue while attempting to include my spec.ts files in sonarqube for code coverage analysis. However, my Jenkins build is failing due to specific spec.ts files. Is there a way to exclude these particular spec.ts files and include ...

Tips for accessing the current state/value in a third-party event handler?

Consider the following scenario: function MapControl() { const [countries, setCountries] = useContext(CountriesContext) useEffect( () => { ThirdPartyApi.OnSelectCountry((country) => { setCountries([...countries, country]) }) }) ...

Implementing multiple filters for object arrays in Angular 8

On my current project, I am interested in implementing multiple filters. The filters I want to use include price range, type, and uploaded date. For uploaded date, I have a checkbox with options for Today, Last 2 days, Last 7 days, and Any. When it come ...

Searching for city and postal code through the Google Maps API is a straightforward process

Is there a way to extract the city and postal code from the Google Maps API? Here is my current code: if (place.address_components) { code = [place.address_components[0].types[0].postal_code]; alert(code); document.getEleme ...

Assistance needed with implementing jQuery tabs

I'm looking to add a link that takes me directly to content within a non-default tab on another page. Here's the code snippet that explains what I need: My Code: This is from my profile_edit.php page: The javascript: <script src="Javascrip ...

Using Set in combination with useRef: A Beginner's Guide

Trying to implement Set with useRef. Below is my attempt. export default function App() { const data = useRef<Set<string>>(new Set()); const add = () => { data.current = new Set([...Array.from(data.current), ...

Tips for obtaining two arrays from one single array

I have received the following array data from a form submission. [filters] => Array ( [label] => Array ( [0] => label1 [1] => label2 ) [na ...

What is the best location to initialize an array of Class in Android Studio?

I keep encountering this error message when attempting to run my code. (I've excluded most of the other lines for clarity) 03-26 22:23:51.800 2425-2425/? E/RCPManagerService: PackageReceiver onReceive() Failed to load meta-data, NullPointer: null 03 ...

IE users experiencing issues with parseInt conversion

It seems pretty simple at first glance, but I'm struggling with parsing a date string from a disabled field. I've tried splitting it by the forward slash and converting it to a number using parseInt, but nothing seems to work. I've spent hou ...

What is the best method for passing information to my frontend JavaScript files using Express?

When using ejs to render my html pages, I pass in data in the following manner: collection.find({}).toArray( function (err, results) { res.render('index', { results: results, ...

Implementing change event to activate select dropdown with jQuery

Is there a way to modify the code so that select2 and select3 are disabled by default, but become enabled only when an option is selected in the previous select dropdown (excluding the placeholder "Select your option")? In addition, I want the first place ...

Create styles for each component based on their specific props when designing a customized Material-UI theme

I am having trouble styling the notchedOutline of a disabled <OutlinedInput /> in my custom MUI theme. My goal is to make the border color lighter than the default color when the input is disabled. Here is what I have attempted so far: const theme = ...

Error when parsing JSON due to the presence of backslashes within the serialized object

When trying to call a server side function and parse the response in client side using JavaScript and Ajax, I encountered a parse error. It seems that the issue lies with the backslash that the JavaScriptSerializer adds to serialize the object. The respons ...

Creating a Form in a Popup with Bootstrap

I have implemented Bootstrap on my website. Check it out at: hubb.tekkkz.com I am facing an issue where, when clicking on the login/register button on the right, the modal pops up. However, the user input elements within the modal are not taking up the ful ...

Sending a PHP variable to a JavaScript function when calling it on a different webpage

As I am working on a code that involves three files, let me break it down for you. The files in question are referred to as a, b, and c. We have "File a," which is an HTML file, "File b," an HTM file, and finally, "file c," which is a PHP file. In "File a ...

What is the reason that try/catch cannot handle errors thrown in the Promise constructor?

My code is encountering an unhandledRejection error and I'm having trouble understanding why. If the Error is thrown within a try/catch block, shouldn't it be caught by the catch expression? async function main () { try { await run(throwEr ...

Searching for a jQuery plugin that can dynamically rearrange tables while automatically updating their corresponding IDs

Is there a way in jQuery to dynamically move tables around on a webpage? Currently, I have implemented a button that clones a hidden table when needed and another button to delete unwanted tables. Now, I am looking to incorporate a feature that allows the ...

What is the best way to refresh a page during an ajax call while also resetting all form fields?

Each time an ajax request is made, the page should refresh without clearing all form fields upon loading Custom Form <form method='post'> <input type='text' placeholder='product'/> <input type='number&a ...

Stop React Form from automatically submitting by preventing automatic submission

I am currently facing an issue with a form that includes a rich text editor and a submit button. The problem arises when the style buttons in the rich text editor are clicked, causing the form inputs to submit unintentionally. My goal is to prevent this b ...