My goal is to make a little program that understands human words.
I decided to start out with simple math before making other stuff but something is wrong.
So far the human reader can do addition, but I want it do more operations like subtraction, multiplication, division, etc. I have this part of the code that handles cases, basically if you tell it to 'add ...' it should add, you get the idea, And it looks like this:
switch (operator) {
case "add":
return numbers.reduce((a, b) => Number(a) + Number(b));
Great, so I figured I should just make another case and just do "subtract" and just do Number(a) - Number(b) right?
Well thats where it goes flop, if I tell it to subtract 2 from 5, it gives me a response that looks like this:
undefined
When what I want it to say is:
-3
How can I solve this issue?
Full Source Code:
function output(func) {
console.log(func)
}
function read(str) {
const dl = str.split(' ');
const operator = dl.shift(x => x.includes("add", "sub", "mul", "div"))
const numbers = dl.filter(x => Number(x))
switch (operator) {
case "add":
return numbers.reduce((a, b) => Number(a) + Number(b));
case "subtract":
return numbers.reduce((a, b) => Number(a) - Number(b));
}
}
const result = read(
"add 6 and 4"
)
output(result)
Looks like it works fine.
function output(func) {
console.log(func)
}
function read(str) {
const dl = str.split(' ');
const operator = dl.shift(x => x.includes("add", "sub", "mul", "div"))
const numbers = dl.filter(x => Number(x))
switch (operator) {
case "add":
return numbers.reduce((a, b) => Number(a) + Number(b));
case "subtract":
return numbers.reduce((a, b) => Number(a) - Number(b));
}
}
output(read(
"add 6 and 4"
))
output(read(
"subtract 6 and 4"
))
output(read(
"subtract 2 and 5"
))
output(read(
"sub 2 and 5"
))
Related
I need to execute an expression according to Order of Operations, and I can't figure out how to resolve the side-by-side brackets.
I am receiving an expression as a string ->
"(add (multiply 4 5) (add 13 1))"
I can't figure out how to resolve this side by side case.
How I have it working for a case where everything is nested by grabbing the innermost brackets and then solving the next like this:
// Find innermost equasion
const findInnerEq = (str) =>
str.substring(str.lastIndexOf("(") + 1, str.lastIndexOf(")"));
// Find Brackets RegEx
const brakets = /(?<=\().*(?=\))/g;
// Changing RegEx function
const changeRE = (str) =>
str.slice(str.lastIndexOf("(") + 1, str.indexOf(")"));
// Return calculation
const calculate = (str) => {
let exp = findInnerEq(str).toLowerCase().split(" ");
let calc = exp
.slice(1)
.map((element) => parseInt(element))
switch (exp[0]) {
case "add":
if (calc.length > 2){
return calc.reduce((acc, cur) => acc + cur, 0);
}
return calc[0] + calc[1]
break;
case "multiply":
return calc.reduce((acc, cur) => acc * cur, 1);
break;
default:
console.log("Please enter valid expression");
process.exit();
}
};
// Recursive function
const calculator = (str) => {
let curString;
if (str.match(brakets)) {
curString = str;
let changingReg = `\(${changeRE(curString)}\)`;
curString = curString.replace(changingReg, calculate(curString));
return calculator(curString);
} else {
return str;
}
};
console.log(calculator("(add 2 (multiply 2 2))"));
console.log(calculator("(add (multiply 2 2) (add 2 2)"));
How can I deal with the side-by-side brackets?
Well, it looks like a classic problem from CS, and you are approaching it wrong.
What you should do instead, is use stacks, pushing items to them until you meet ')', which will tell you to execute the action on the stack collected so far.
Here is one of explanations https://orkhanhuseyn.medium.com/what-are-stack-based-calculators-cf2dbe249264
try this:
let arr = str.split("(").join("|:|:|:|").split(")").join("|:|:|:|").split("|:|:|:|")
//arr is now an array that has been split at both ( and )
// the middle value: arr[arr.length/2]
//evaluate it, and then combine it with arr[arr.length/2+1] and arr[arr.length/2-1]
//continue the cycle until your whole expression is evaluated
There is one project challenge on freecodecamp about building a calculator and I just managed to pass all the tests but when looking back on my code, the section dealing with the operations are barely readable. I've read some articles online regarding how to reduce the complexity of conditionals and the principles to keep in mind for more easy-to-understand logic.
However, figuring out the achievable logics for this task in javascript is quite challenging to me now. I was trying to meet two conditions with this section of code as follows:
User Story #13: If 2 or more operators are entered consecutively, the operation performed should be the last operator entered (excluding the negative (-) sign). For example, if 5 + * 7 = is entered, the result should be 35 (i.e. 5 * 7); if 5 * - 5 = is entered, the result should be -25 (i.e. 5 * (-5)).
User Story #14: Pressing an operator immediately following = should start a new calculation that operates on the result of the previous evaluation.
Here is the link to the page for this particular challenge and
this is the link to the code I wrote by far.
Is there any tips and advice on refining the code or other approaches for coping with this part?
handleOperation(event){
const {value}=event.target
const displayLength=this.state.display.length
const condition1=this.state.display=="+"||this.state.display=="-"||this.state.display=="×"||this.state.display=="÷"||this.state.display==""
const condition2=/^\d*\.?\d*$/.test(this.state.input)&&!/=/.test(this.state.display)
const condition3=this.state.input=="-"&&(this.state.display.charAt(displayLength-2)=="+"||this.state.display.charAt(displayLength-2)=="-"||this.state.display.charAt(displayLength-2)=="×"||this.state.display.charAt(displayLength-2)=="÷")
const condition4=this.state.input=="-"&&value=="-"&&!/=/.test(this.state.display)
const condition5=this.state.input=="-"&&value!=="-"&&!/=/.test(this.state.display)
const condition6=this.state.input!=="-"&&value!=="-"&&!/=/.test(this.state.display)
const condition7=this.state.input!=="-"&&value=="-"&&!/=/.test(this.state.display)
const condition8=/=/.test(this.state.display)
console.log(this.state.display.replace(/=/,"$'"))
if(condition1){
this.setState({
input:value,
display:value
})
}else if(condition2){
this.setState({
input:value,
display:this.state.display+value
})
}else if(condition3){
this.setState({
input:value,
display:this.state.display.replace(/[\+\-×÷]-$/,value)
})
}
else if(condition4){
this.setState({
input:value,
display:this.state.display.replace(/(?<=\d)-$/,"--")
})
}else if(condition5){
this.setState({
input:value,
display:this.state.display.replace(/(?<=\d)-/,value)
})
}else if(condition6){
this.setState({
input:value,
display:this.state.display.substring(0,displayLength-1)+value
})
}else if(condition7){
this.setState({
input:value,
display:this.state.display+value
})
} else if(condition8){
this.setState({
input:value,
display:this.state.display.substring(this.state.display.indexOf("=")+1)+value
})
}
}
Break down the process to the basic steps:
get the operation(s) from the string
get the numbers from the string
do the operation
Here's a snippet for this:
const calcs = [
"5 + 15",
"5 - 5",
"5 - - 5",
"5 / + 5",
"5 / - 5",
"5 / * + 5",
"5 / + * 5",
]
const container = document.getElementById("container");
// getting the operation(s) from the string
const getOperation = (calc) => {
const regex = /d*([+|\-|\*|\/]+)d*/g
const listOfOperations = calc.match(regex)
let operation = listOfOperations.pop()
let nextIsNegative = false
// if the operation is "-" and it wasn't the last item
if (listOfOperations.length && operation === "-") {
operation = listOfOperations.pop()
nextIsNegative = true
}
return {
operation,
nextIsNegative,
}
}
// getting the numbers from the string
const getNumbers = (calc) => {
const regex = /\d+/g
return calc.match(regex)
}
// doing the calculation
const doOperation = ({
operation,
nextIsNegative
}, [num1, num2]) => {
const operationObj = {
"+": (a, b) => a + b,
"-": (a, b) => a - b,
"*": (a, b) => a * b,
"/": (a, b) => a / b,
}
const n1 = Number(num1)
const n2 = nextIsNegative ? Number(num2) * -1 : Number(num2)
return operationObj[operation](n1, n2)
}
(function(calcs) {
const html = calcs.map((calc, i) => {
const operation = getOperation(calc)
const numbers = getNumbers(calc)
const result = doOperation(operation, numbers)
return `
<div id="in${i}">${calc}</div>
<div id="operation${i}">${JSON.stringify(operation)}</div>
<div id="result${i}">${ result }</div>`
})
container.innerHTML = html.join('')
})(calcs);
#container {
display: grid;
grid-template-columns: 80px 1fr 80px;
}
<div id="container"></div>
I cant seem to get my calculator to chain multiple operators together for example 5x5x5 should equal 125 but it just calculates 5x5 and will no longer calculate decimal numbers. Could anyone point me in the correct direction.
I have tried to assign the result to the firstNum but it seems to break the code.
button.forEach((button) =>
button.addEventListener('click', ()=> displayTotal(button.innerHTML)));
clearBtn.addEventListener('click', clear);
decmialBtn.addEventListener('click', appendDecimal);
functionBtn.forEach((button) =>
button.addEventListener('click', () => setOperator(button.innerHTML)));
equalsBtn.addEventListener('click', calculate)
let firstNum = "";
let secondNum = "";
let operatorSelection = "null";
let result = "";
function add(a, b){
return a + b
}
function subtract(a,b){
return a - b
}
function divide (a,b)
{
return a / b
}
function times (a,b){
return a*b
}
function operator(operator, numa, numb) {
switch(operator){
case '+':
return add(numa, numb);
break;
case '-':
return subtract(numa, numb);
break;
case '/':
return divide(numa,numb);
break;
case '*':
return times(numa,numb)
break;
}
}
function displayTotal (number){
userDisplay.value += number;
}
function clear (){
userDisplay.value = "";
}
function appendDecimal(){
userDisplay.value += ".";
}
function setOperator(operator){
firstNum = parseInt(userDisplay.value);
operatorSelection = operator;
result = firstNum;
clear()
}
function calculate(){
for (i = 0; i < 100; i++)
secondNum = parseInt(userDisplay.value);
result = operator(operatorSelection, firstNum, secondNum);
userDisplay.value = result;
[i];
}
For a simple JS calculator you could use the eval() function and it will handle all the operators for you taking PEMDAS in consideration, but you have to ensure the inpput is valid or it you won't work.
I have one on my Github if want an example:
https://github.com/gustavo-shigueo/calculator
Note: don't worry about the regexes I used, they are there just to prevent the user from typing stuff that would break the calculator
Here is an example of how I would do it:
operations = [
["*", (a, b) => +a * +b],
["/", (a, b) => +a / +b],
["+", (a, b) => +a + +b],
["-", (a, b) => +a - +b],
];
const calc = calcString => {
const split = [...calcString].reduce((prev, cur) => Number.isInteger(+cur) && Number.isInteger(+prev[prev.length - 1]) ? [...prev.slice(0, -1), prev[prev.length - 1] + cur] : [...prev, cur], [""]);
operations.forEach(([operator, funct]) => {
for (let i = 1; i < split.length - 1; i++) {
if (split[i] === operator) {
split[i - 1] = funct(split[i - 1], split[i + 1]);
split.splice(i, 2);
i--;
}
}
})
return split;
};
It doesn't support numbers with a dot/comma in them (e.g. 3.13) and no braces.
some explanation:
const split, I split the given string in numbers and operations, "3+45*4" would result in ["3", "+", "45", "*", "4"].
go over each operation in the given order to first do the "point calculation" and then + and -.
we go over the in 1. created array and look for our operation.
if we find one, we lool at the number before and after the operation and calculate the result given the 2 numbers and our operation type.
we overwrite those 3 elements with the result of our calculation.
we are done if all operations are done
I also have a more advanced version if you are interested
I have a task where I should create 3 variables, 2 of them will be numbers (2,3) and the 3rd will be '*' or '/' sign string.
I need to write a function that will return the answer of 2*3 and 2/3 by using the 3 variables only for the outcome.
I have no idea how to use the variable that contains a string, and that string to perform the operation of subtract or multiply.
function multiply (a , b ,c ) {
}
console.log (multiply(4, (*) , 5 )) ;
I expect the outcome to be 4* 5 and 4/5
You're trying to pass an operator as a parameter to a function, which isn't possible in javascript. You can still make this function though, but using strings as an alternative.
function multiply(a, b, op) {
if (op === '*') return a * b;
if (op === '/') return a / b;
}
console.log(multiply(2, 5, '*')); // should return 10
console.log(multiply(2, 5, '/')); // should return 0.4
const handlers = {
'*': (a, b) => { return a * b; },
'/': (a, b) => { return a / b; },
}
function multiply (a , b ,c ) {
return handlers[b](a, c);
}
Put it on if condition and match ur sign
function multiply (a , b ,c ) {
return c === '*' ? a*b : a/b
}
console.log (multiply(4, 5, '/' )) ;
Hope it help
const multiply = (num1, num2, calc) => `${num1}${calc}${num2}`
console.log(multiply(1,2,"*"))
I am programming a calculator that takes a string representing a calculation and outputs the result (like the eval function).
At some point in my code I define the meaning of the different operations like this:
const _ops = [
[
["^", (a, b) => (+a) ** +b],
],
[
["*", (a, b) => +a * +b],
["/", (a, b) => +a / +b],
["%", (a, b) => +a % +b],
],
[
["+", (a, b) => +a + +b],
["-", (a, b) => +a - +b],
],
];
As you can see I am repeating the function part every time while only one character changes (except for the first time...)
(a, b) => +a ${operation} +b
Do you have any idea how I could do this without repeating the function declaration every time?
PS: If you can think of a better title, feel free to change it.
No, this is not possible in JavaScript without eval. This is because there is no way to treat an operator as a function. This is not the case e.g. in Haskell, where (*) represents the multiplication function, which you can carry around as a value, apply a value to get a partially-applied operator, and apply another value to get the result.
Using eval would look kind of like this.
const dynamicCalculation = (a ,b, operator) => {
if (operator === "^") operator = "**"
return eval("${+a} ${operator} ${+b}")
}
usage:
dynamicCalculation(1,2,"+") // => 3
dynamicCalculation(1,2,"-") // => -1
dynamicCalculation(1,2,"*") // => 2
switch:
const dynamicCalculation = (a ,b, operator) => {
let output;
switch(operator){
case "+":
output = a + b;
break;
case "-":
output = a - b;
break;
case "*":
output = a * b;
break;
case "/":
output = a / b;
break;
case "^":
output = a ** b;
break;
case "%":
output = a % b;
break;
}
return output
}