Writing a calculator function - in the most functional programming way(javascript) - javascript

I am trying out a task from codewars and wanted to write in a functional programming way in javascript. I have some questions regarding my functions and how the code can be written in a better way.
The task itself is to build a calculator function. It will accept an input in the format:
'..... + ...'
The calculator must split the string by the middle character signifying the operation and then the two string that are left will be the two values. In the example above first value will be 5 and the second 3. Once this is done, depending on the operator, do the action - either addition, multiplication etc.
Here is my code:
function dotCalculator(equation) {
function returnSymbol(input) {
if (input.includes(' + ')) {
return ' + ';
} else if (input.includes(' - ')) {
return ' - ';
} else if (input.includes(' * ')) {
return ' * ';
} else if (input.includes(' / ')) {
return ' / ';
}
}
let symbolOf = returnSymbol;
let result = equation.split(symbolOf(equation)).map(x => x.length);
// Array.prototype.add = function(){
// return this[0] + this[1];
// }
}
I know my code is not done yet. I am trying to understand how to properly finish it having the functional programming way of thinking in mind. Maybe prototypal inheritance would a bit overkill. I am looking for some ideas from anyone who would lend a hand. I tried writing a more complex reduce after
let arrMine = equation.split(symbolOf(equation)).map((x) => x.length);
but it seemed way too messy. Any help would be greatly appreciated.

I'm very much a functional programming noob, the pipe function being here is probably kind of gratuitous and I might have taken the ..... + ... example overly literally, but here's an attempt:
const arith = {
'+': (a, b) => a + b,
'-': (a, b) => a - b,
'*': (a, b) => a * b,
'/': (a, b) => a / b,
};
const pipe = (...fns) => (arg) => fns.reduce((res, fn) => fn(res), arg);
const get_input_elements = (input) => input.split(' ');
const get_number = (dots) => dots.length;
const get_numbers = ([str_a, op, str_b]) =>
[get_number(str_a), op, get_number(str_b)];
const apply_arith = ([a, op, b]) => arith[op](a, b);
const calc = pipe(
get_input_elements,
get_numbers,
apply_arith
);
console.log(calc('..... + ...'));
console.log(calc('..... - ...'));
console.log(calc('...... / ..'));

In this example are functional programs that can evaluate simple arithmetic -- adding, subtracting, multiplying, or dividing two numbers.
Details are commented in example below
Note: prefix any negative number being passed into calc() with an underscore _ instead of a hyphen -
// Utility function
const log = data => console.log(JSON.stringify(data));
// Arithmetic functions
const sum = (a, b) => (+a) + (+b);
const dif = (a, b) => a - b;
const pro = (a, b) => a * b;
const quo = (a, b) => a / b;
/**
* Calculate a simple formula a+b, a-b, a*b, or a/b.
* #param {string} formula - Pattern:
* "numberOPERANDnumber" ex. "5+5"
* Use an underscore to prefix negative numbers.
* #returns {number} Result of formula
*/
const calc = formula => {
// Declare variables
let result, f, a, b, op;
/*
Convert string into an array of strings.
[number, operand, number]
Replace any _ with - (see #param)
*/
f = formula.split(/([+\-*/])/)
.map(ab => ab.replace('_', '-'));
/*
Convert string of numbers into real numbers.
*/
a = parseFloat(f[0]);
b = parseFloat(f[2]);
op = f[1];
/*
Check if >a< and >b< are real numbers and if the input string was split
into 3 strings.
*/
if (Number.isNaN(a) || Number.isNaN(b) || f.length != 3) {
return;
}
// >op< determines the method of resolving the formula
switch (op) {
case '+':
result = sum(a, b);
break;
case '-':
result = dif(a, b);
break;
case '*':
result = pro(a, b);
break;
case '/':
result = quo(a, b);
break;
default:
return;
}
return result;
};
log(calc('5+5'));
log(calc('_10-7')); // That's a -10 (see #param)
log(calc('5*9'));
log(calc('51/3'));

Related

Refactoring JavaScript (Swtich & Function)

I'm a beginner at coding, and I'm studying JS. I'd like to know how to write a function inside a switch in this code below (if possible), turning the code smaller.
I tried to place the funtion for each operation inside of the switch, but it never worked.
Help me to improve my code. Thank you!
//Calculator of Basic Operations
function addition(a, b) {
return (a + b);
}
function subtraction(a, b) {
return (a - b);
}
function multiplication(a, b) {
return (a * b);
}
function division(a, b) {
return (a / b);
}
console.log('Choose the number for the operation you want to use.');
console.log('1 - Addition');
console.log('2 - Subtraction');
console.log('3 - Multiplication');
console.log('4 - Division');
let calcAB = prompt('Operation: ');
switch (calcAB) {
case '1':
a = Number(prompt('Enter the value for A: '));
b = Number(prompt('Enter the value for B: '));
console.log(`The addition result is "${addition(a, b)}"`);
break;
case '2':
a = Number(prompt('Enter the value for A: '));
b = Number(prompt('Enter the value for B: '));
console.log(`The subtraction result is "${subtraction(a, b)}"`);
break;
case '3':
a = Number(prompt('Enter the value for A: '));
b = Number(prompt('Enter the value for B: '));
console.log(`The multiplication result is "${multiplication(a, b)}"`);
break;
case '4':
a = Number(prompt('Enter the value for A (dividend): '));
b = Number(prompt('Enter the value for B (divisor): '));
console.log(`The division result is "${division(a, b)}"`);
break;
}
The only things that change between the cases are
The function called
The name of the operation called
The (dividend) (divisor) for /
I'd use an array for the functions and operator names instead - for example, [0] will refer to (a, b) => a + b, so that way you just have to subtract 1 from the number chosen by the user to get to the function. To get a and b, interpolate (dividend) (divisor) only if the case is 4 - but it can all be done at once.
const fns = [
[(a, b) => a + b, 'addition'],
[(a, b) => a - b, 'subtraction'],
[(a, b) => a * b, 'multiplication'],
[(a, b) => a / b, 'division']
];
const op = prompt('Operation: ');
const item = fns[op - 1];
if (!item) {
throw new Error('Invalid');
}
const a = Number(prompt(`Enter the value for A${op === '4' ? ' (dividend)' : ''}: `));
const b = Number(prompt(`Enter the value for b${op === '4' ? ' (divisor)' : ''}: `));
console.log(`The ${item[1]} result is ${item[0](a, b)}`);
Don't make your code complex in order to make it smaller, it makes it more confusing and misses the point, which is to make you understand the syntax and what you are doing

Calculator - issue with multiple digit / operators operations

Newbie here, I am stuck with my Calculator project and cannot continue. There's something wrong with my code an cannot figure out what.
So the issue involves operations on multiple digit numbers (e.g. 22) as well as multiplying / dividing after summing / deducting.
Previously I was struggling with multiple operations in general, but it seems to be now working (with 1 digit numbers only though). Whenever I insert, e.g. 23, the function right away assigns 23 to both first and second operands and gives me 46.
The same thing happens when I use an operator in the 2nd operation which is different than the one used in the first operation (e.g if I use sum operator twice and then deduct, my result will be zero as the result gets assigned to both operands and continues with the operation).
Could someone advise what is the issue with this code? I think it's because of "operand1" variable. The expected behavior would be for the function to stop after each click, but then as soon as the operand1 value changes to "empty" again, the code continues. I tried to override this but nothing I come up with works, I feel like I'm missing something basic.
Thanks in advance!
let add = (a, b) => a + b;
let subtract = (a, b) => a - b;
let multiply = (a, b) => a * b;
let divide = (a, b) => a / b;
function operate(operator, a, b) {
if (operator === '+') {
return add(a, b);
} else if (operator === '-') {
return subtract(a, b);
} else if (operator === '*') {
return multiply(a, b);
} else { return divide(a, b); }
};
const display = document.querySelector("h1"); // display
const numButtons = document.querySelectorAll(".num"); // 0 - 9
const operateButtons = document.querySelectorAll(".operator"); // +, -, *, /
const equals = document.querySelector('#equals') // =
const clearBtn = document.querySelector('#clear'); // AC
let displayValue = []; // add clicked numbers to array
let displayNumbers; // joined array
let operations = ['a','operator','b'];
let operand1 = "empty"; // value that shows if 1st num has already been selected
numButtons.forEach((button) => {
button.addEventListener('click', function() {
displayValue.push(this.innerText);
displayNumbers = displayValue.join("");
display.textContent = displayNumbers;
operateButtons.forEach((button) => {
button.addEventListener('click', function insertOperand() {
if(operand1 === "empty") {
operations[0] = Number(displayNumbers);
operations[1] = this.textContent;
displayValue = [];
operand1 = "inserted";
} else if (operand1 === "inserted") {
operations[2] = Number(displayNumbers);
result = operate(operations[1],operations[0],operations[2]);
display.textContent = result;
displayNumbers = result;
displayValue = [];
operand1 = "empty";
button.removeEventListener('click',insertOperand);
}
});
});
});
});

perform calculation according to formula and object as parameter

I have created getResult function to perform calculation according to formula. is there any way to perform this calculations
please let me know if you have any solution.
Thanks in Advance
let formula = "a*b";
let parameters = {a:3,b:4}
let getResult = function(formula, parameters){
}
A simple calculator that doesn't rely on eval:
let formula = "a*b";
let parameters = {a:3,b:4}
function getResult(formula, parameters){
const operator = formula.match(/[+-\/*]{1}/)[0];
const {a, b} = parameters;
switch(operator) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return a / b;
}
}
const result = getResult(formula, parameters);
console.log(result);
Try this. Though "eval" is something to be avoided.
let formula = "a*b";
let parameters = {a:3,b:4}
let getResult = function(formula, parameters){
let cal = [...formula].map(d => parameters[d] || d).join('')
return eval(cal)
}
console.log(getResult(formula, parameters))

How do I add two numbers in JavaScript "without using `+` or `-` operators"?

I know an alternative to using the + sign for addition is to do something like this:
int add(int a, int b)
{
if(b == 0)
return sum;
sum = a ^ b;
carry = (a & b) << 1;
return add(sum,carry);
}
But I have two problems:
This is C++, not JavaScript. Is this supported in JavaScript?
It's obvious the whole trick is in ^ & <<, but I don't know how to start looking for them in JavaScript, because I don't know what they are called.
What should I be googling for even?
I tried to write this in JavaScript ... but seems I miss something
var getSum = function(a, b) {
return (a ^ b, (a & b) << 1)
};
We will use bitwise operators and will use recursion.
We use this method when we have a few low resources. Read more about when to use this method!
var getSum = function(a, b) {
if (b == 0) {
return a;
} else {
return getSum(a ^ b, (a & b) << 1)
}
};
ECMAScript 6 one-liner solution as suggested by #PatrickRoberts:
const getSum = (a,b) => b ? getSum(a ^ b, (a & b) << 1) : a;
Another solutions:
2- Arrays technique Array.prototype.fill()
const getSum = (a, b) => {
const firstArr = new Array(a).fill(true);
const secondArr = new Array(b).fill(true);
return firstArr.concat(secondArr).length
}
3- workaround to use plus sign without writing it:
const getSum = (a, b) => eval(''.concat(a).concat(String.fromCharCode(0x2B)).concat(b));
Well ok i am answering to the question as clearly described in the header. No + and no - operations right..? Yet... not with bitwise but with pure math should be a valid answer i suppose.
var x = 1,
y = 2,
sum = Math.log2(2**x * 2**y);
console.log(sum);
const add = (a, b) => new Function('a', 'b', `return ${a} ${String.fromCharCode(43)} ${b}`)(a, b);
We can implement same using while loop. We have to shift the carry to left and add it to binary sum of numbers till there will no carry. (As we follows the practice in addition of decimals.)
function getSum(a, b){
while(b!=0){
var carry = a&b; //calculate if is there any carry we need to add
a = a^b; // a is used to hold the sum
b = carry<<1; //b is used to hold left shift carry
}
return a;
}
document.write(getSum(7, 5))
It's possible to use arrays structures to perform a sum operation.
function getSum(a, b){
return Array(a).concat(Array(b)).length / 100;
}
Each input is coerced to an array, for instance, an input of value 5 would be coerced to an array of 5 elements. After coercing both inputs, the arrays are joined into a single array. The length of the final array is returned, by dividing to 100 to deal with the sum of decimal values.
Now, let's try to be defensive about invalid input cases, such as strings or falsy values.
const DEFAULT_NUMBER_VALUE = 0;
const DEFAULT_PRECISION = 100;
function parseAddInput(input){
if (!input) {
return DEFAULT_NUMBER_VALUE;
}
if (typeof input === 'string'){
input = parseInt(input);
}
const roundedNumber = Math.round(input * (10 * DEFAULT_PRECISION));
return roundedNumber;
}
function getSum(a, b){
return Array(
parseAddInput(a)
).concat(
Array(parseAddInput(b))
).length / 100;
}
function add(number1, number2){
return getSum(number1, number2);
}
The same approach as #PatrickRoberts suggested, but without recursion:
const add = (a, b) => {
let c;
while (a !== 0) {
c = b & a;
b = b ^ a;
c = c << 1;
a = c;
}
return b;
};

Parse arithmetic expression with javascript

Is there a simple way, with javascript, to convert the following expression
e*((a*(b+c))+d)
into something like
multiply(e, add(multiply(a, add(b,c)), d))
The expression would be stored in a string. I'm open to any solution that will avoid me to write my own parser (library, buitl-in capabilities, ...)
EDIT: I should have precised that I don't actually want to use multiply and add functions, the purpose of this is to define my own function to replace multiply and add and perform custom operations on the variables
The expression you are trying to parse into an abstract syntax tree is a context-free expression. This means that you need a context-free grammar to be able to parse it. So let's create a parser.
To simplify the parsing we'll separate the lexical analysis phase. Hence the first thing we need is to create a lexer. Luckily there are a lot of handy lexer libraries available. We'll use the this one:
https://github.com/aaditmshah/lexer
So here's the lexical analyzer:
var lexer = new Lexer;
lexer.addRule(/\s+/, function () {
/* skip whitespace */
});
lexer.addRule(/[a-z]/, function (lexeme) {
return lexeme; // symbols
});
lexer.addRule(/[\(\+\-\*\/\)]/, function (lexeme) {
return lexeme; // punctuation (i.e. "(", "+", "-", "*", "/", ")")
});
Next we create a parser. We'll use the following implementation of Dijkstra's shunting yard algorithm for parsing:
https://gist.github.com/aaditmshah/6683499
So here's the parser:
var factor = {
precedence: 2,
associativity: "left"
};
var term = {
precedence: 1,
associativity: "left"
};
var parser = new Parser({
"+": term,
"-": term,
"*": factor,
"/": factor
});
Finally we create a parse function as follows:
function parse(input) {
lexer.setInput(input);
var tokens = [], token;
while (token = lexer.lex()) tokens.push(token);
return parser.parse(tokens);
}
Now you simply call parse to get a parsed stream of tokens in postfix notation:
var output = parse("e*((a*(b+c))+d)");
alert(output.join(" ")); // "e a b c + * d + *"
The advantage of postfix form is that you can easily manipulate it using a stack:
Push e onto the stack.
Push a onto the stack.
Push b onto the stack.
Push c onto the stack.
Pop b and c and push b + c onto the stack.
Pop a and b + c and push a * (b + c) onto the stack.
Push d onto the stack.
Pop a * (b + c) and d and push a * (b + c) + d onto the stack.
Pop e and a * (b + c) + d and push e * (a * (b + c) + d) onto the stack.
Similarly it's easy to create the output you want using stacks too. It the same steps. You only push different values back onto the stack for different operations.
See the demo: http://jsfiddle.net/d2UYZ/2/
Edit 1: I was so bored that I solved the problem for you:
var stack = [];
var operator = {
"+": "add",
"-": "subtract",
"*": "multiply",
"/": "divide"
};
parse("e*((a*(b+c))+d)").forEach(function (c) {
switch (c) {
case "+":
case "-":
case "*":
case "/":
var b = stack.pop();
var a = stack.pop();
stack.push(operator[c] + "(" + a + ", " + b + ")");
break;
default:
stack.push(c);
}
});
var output = stack.pop();
alert(output);
The output is (as you expect) the string "multiply(e, add(multiply(a, add(b,c)), d))". See the demo: http://jsfiddle.net/d2UYZ/4/
Edit 2: If you need to evaluate the expression you could do that easily too. All you need is a context mapping symbols to values and functions for each operator:
var stack = [];
var context = {
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5
};
var operator = {
"+": function (a, b) { return a + b; },
"-": function (a, b) { return a - b; },
"*": function (a, b) { return a * b; },
"/": function (a, b) { return a / b; }
};
parse("e*((a*(b+c))+d)").forEach(function (c) {
switch (c) {
case "+":
case "-":
case "*":
case "/":
var b =+ stack.pop();
var a =+ stack.pop();
stack.push(operator[c](a, b));
break;
default:
stack.push(context[c]);
}
});
var output = stack.pop();
Thus the expression e*((a*(b+c))+d) becomes 5*((1*(2+3))+4) which evaluates to 45. See the demo: http://jsfiddle.net/d2UYZ/6/
You cannot do this with eval as has been suggested, because you would not be able to use your custom add and multiply functions that way. You could parse out all of the operators with regular expressions, but it would not be easy.
You would have to make sure you got the order of operations correct, and break it into many steps.
The basic logic of it would be:
Define your add and multiply functions.
Define a function that takes a string of numbers and operators (without parentheses) and splits it into binary operations (ie. '1 + 7' or '5 * 3') with regular expressions, that can be passed to your add and multiply functions. This would have to be done recursively, following your desired order of operations for your custom math, in other words, if you get '5 + 3 * 2' you will have parse out '3 * 2' and evaluate that before using its result to add to 5 (assuming your order would be multiply first).
Define a function that looks for parentheses and recursively finds the innermost set and passes it to function 2 above to be evaluated.
Pass your input string to function 3 above and hope that you got all of the recursive logic and regular expressions correct.
I think the better way is define your own functions like this:
multiply = function(a, b) {
return a * b;
}
add = function(a, b) {
return a + b;
}
This examples is limited to only two numbers, but it can be scaled using arguments.
Fiddle

Categories

Resources