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);
}
});
});
});
});
Related
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'));
I need a js sum function to work like this:
sum(1)(2) = 3
sum(1)(2)(3) = 6
sum(1)(2)(3)(4) = 10
etc.
I heard it can't be done. But heard that if adding + in front of sum can be done.
Like +sum(1)(2)(3)(4). Any ideas of how to do this?
Not sure if I understood what you want, but
function sum(n) {
var v = function(x) {
return sum(n + x);
};
v.valueOf = v.toString = function() {
return n;
};
return v;
}
console.log(+sum(1)(2)(3)(4));
JsFiddle
This is an example of using empty brackets in the last call as a close key (from my last interview):
sum(1)(4)(66)(35)(0)()
function sum(firstNumber) {
let accumulator = firstNumber;
return function adder(nextNumber) {
if (nextNumber === undefined) {
return accumulator;
}
accumulator += nextNumber;
return adder;
}
}
console.log(sum(1)(4)(66)(35)(0)());
I'm posting this revision as its own post since I apparently don't have enough reputation yet to just leave it as a comment. This is a revision of #Rafael 's excellent solution.
function sum (n) {
var v = x => sum (n + x);
v.valueOf = () => n;
return v;
}
console.log( +sum(1)(2)(3)(4) ); //10
I didn't see a reason to keep the v.toString bit, as it didn't seem necessary. If I erred in doing so, please let me know in the comments why v.toString is required (it passed my tests fine without it). Converted the rest of the anonymous functions to arrow functions for ease of reading.
New ES6 way and is concise.
You have to pass empty () at the end when you want to terminate the call and get the final value.
const sum= x => y => (y !== undefined) ? sum(x + y) : x;
call it like this -
sum(10)(30)(45)();
Here is a solution that uses ES6 and toString, similar to #Vemba
function add(a) {
let curry = (b) => {
a += b
return curry
}
curry.toString = () => a
return curry
}
console.log(add(1))
console.log(add(1)(2))
console.log(add(1)(2)(3))
console.log(add(1)(2)(3)(4))
Another slightly shorter approach:
const sum = a => b => b? sum(a + b) : a;
console.log(
sum(1)(2)(),
sum(3)(4)(5)()
);
Here's a solution with a generic variadic curry function in ES6 Javascript, with the caveat that a final () is needed to invoke the arguments:
const curry = (f) =>
(...args) => args.length? curry(f.bind(0, ...args)): f();
const sum = (...values) => values.reduce((total, current) => total + current, 0)
curry(sum)(2)(2)(1)() == 5 // true
Here's another one that doesn't need (), using valueOf as in #rafael's answer. I feel like using valueOf in this way (or perhaps at all) is very confusing to people reading your code, but each to their own.
The toString in that answer is unnecessary. Internally, when javascript performs a type coersion it always calls valueOf() before calling toString().
// invokes a function if it is used as a value
const autoInvoke = (f) => Object.assign(f, { valueOf: f } );
const curry = autoInvoke((f) =>
(...args) => args.length? autoInvoke(curry(f.bind(0, ...args))): f());
const sum = (...values) => values.reduce((total, current) => total + current, 0)
curry(sum)(2)(2)(1) + 0 == 5 // true
Try this
function sum (...args) {
return Object.assign(
sum.bind(null, ...args),
{ valueOf: () => args.reduce((a, c) => a + c, 0) }
)
}
console.log(+sum(1)(2)(3,2,1)(16))
Here you can see a medium post about carried functions with unlimited arguments
https://medium.com/#seenarowhani95/infinite-currying-in-javascript-38400827e581
Try this, this is more flexible to handle any type of input. You can pass any number of params and any number of paranthesis.
function add(...args) {
function b(...arg) {
if (arg.length > 0) {
return add(...[...arg, ...args]);
}
return [...args, ...arg].reduce((prev,next)=>prev + next);
}
b.toString = function() {
return [...args].reduce((prev,next)=>prev + next);
}
return b;
}
// Examples
console.log(add(1)(2)(3, 3)());
console.log(+add(1)(2)(3)); // 6
console.log(+add(1)(2, 3)(4)(5, 6, 7)); // 28
console.log(+add(2, 3, 4, 5)(1)()); // 15
Here's a more generic solution that would work for non-unary params as well:
const sum = function (...args) {
let total = args.reduce((acc, arg) => acc+arg, 0)
function add (...args2) {
if (args2.length) {
total = args2.reduce((acc, arg) => acc+arg, total)
return add
}
return total
}
return add
}
document.write( sum(1)(2)() , '<br/>') // with unary params
document.write( sum(1,2)() , '<br/>') // with binary params
document.write( sum(1)(2)(3)() , '<br/>') // with unary params
document.write( sum(1)(2,3)() , '<br/>') // with binary params
document.write( sum(1)(2)(3)(4)() , '<br/>') // with unary params
document.write( sum(1)(2,3,4)() , '<br/>') // with ternary params
ES6 way to solve the infinite currying. Here the function sum will return the sum of all the numbers passed in the params:
const sum = a => b => b ? sum(a + b) : a
sum(1)(2)(3)(4)(5)() // 15
function add(a) {
let curry = (b) => {
a += b
return curry;
}
curry[Symbol.toPrimitive] = (hint) => {
return a;
}
return curry
}
console.log(+add(1)(2)(3)(4)(5)); // 15
console.log(+add(6)(6)(6)); // 18
console.log(+add(7)(0)); // 7
console.log(+add(0)); // 0
Here is another functional way using an iterative process
const sum = (num, acc = 0) => {
if !(typeof num === 'number') return acc;
return x => sum(x, acc + num)
}
sum(1)(2)(3)()
and one-line
const sum = (num, acc = 0) => !(typeof num === 'number') ? acc : x => sum(x, acc + num)
sum(1)(2)(3)()
You can make use of the below function
function add(num){
add.sum || (add.sum = 0) // make sure add.sum exists if not assign it to 0
add.sum += num; // increment it
return add.toString = add.valueOf = function(){
var rtn = add.sum; // we save the value
return add.sum = 0, rtn // return it before we reset add.sum to 0
}, add; // return the function
}
Since functions are objects, we can add properties to it, which we are resetting when it's been accessed.
we can also use this easy way.
function sum(a) {
return function(b){
if(b) return sum(a+b);
return a;
}
}
console.log(sum(1)(2)(3)(4)(5)());
To make sum(1) callable as sum(1)(2), it must return a function.
The function can be either called or converted to a number with valueOf.
function sum(a) {
var sum = a;
function f(b) {
sum += b;
return f;
}
f.toString = function() { return sum }
return f
}
function sum(a){
let res = 0;
function getarrSum(arr){
return arr.reduce( (e, sum=0) => { sum += e ; return sum ;} )
}
function calculateSumPerArgument(arguments){
let res = 0;
if(arguments.length >0){
for ( let i = 0 ; i < arguments.length ; i++){
if(Array.isArray(arguments[i])){
res += getarrSum( arguments[i]);
}
else{
res += arguments[i];
}
}
}
return res;
}
res += calculateSumPerArgument(arguments);
return function f(b){
if(b == undefined){
return res;
}
else{
res += calculateSumPerArgument(arguments);
return f;
}
}
}
let add = (a) => {
let sum = a;
funct = function(b) {
sum += b;
return funct;
};
Object.defineProperty(funct, 'valueOf', {
value: function() {
return sum;
}
});
return funct;
};
console.log(+add(1)(2)(3))
After looking over some of the other solutions on here, I would like to provide my two solutions to this problem.
Currying two items using ES6:
const sum = x => y => (y !== undefined ) ? +x + +y : +x
sum(2)(2) // 4
Here we are specifying two parameters, if the second one doesnt exist we just return the first parameter.
For three or more items, it gets a bit trickier; here is my solution. For any additional parameters you can add them in as a third
const sum = x => (y=0) => (...z) => +x + +y + +z.reduce((prev,curr)=>prev+curr,0)
sum(2)()()//2
sum(2)(2)()//4
sum(2)(2)(2)//6
sum(2)(2)(2,2)//8
I hope this helped someone
I'm stuck on a problem that requires me to display the full workings of a factorial function, for example, if the user wanted to workout 6!, i would need to display: 6 * 5 * 4 * 3 * 2 * 1 = 720. Would i need to use an array for such?
This is what i have so far in order to workout the factorized value of any user given number, although this only outputs the final value, and not the fully expanded working out as i have shown above:
(the variable number contains the user input);
var f = [];
function factorizeFunction(number) { //this is the function that does the factorization calculations
if (number == 0 || number == 1)
return 1;
if (f[number] > 0)
return f[number];
return f[number] = factorizeFunction(number-1) * number;
}
document.getElementById("factorialTest").innerHTML = factorizeFunction(number);
any help on this would be appreciated!
One option is, on each iteration, push to an array which is passed down through the recursive call (or created on the initial call). At the end, return the array, joined by *, and also the sum of the array:
function factorizeFunction(number, arr = []) { //this is the function that does the factorization calculations
if (number == 0 || number == 1) arr.push(number);
else {
arr.push(number);
factorizeFunction(number - 1, arr);
}
return arr.join(' * ') + ' = ' + arr.reduce((a, b) => a * b, 1);
}
document.getElementById("factorialTest").innerHTML = factorizeFunction(5);
<div id="factorialTest"></div>
Use map and join methods.
const factorString = num => {
const nums = new Array(num).fill(0).map((_, i) => num - i);
let res = 1;
nums.forEach(x => res *= x);
return `${nums.join(' * ')} = ${res}`;
}
console.log(factorString(6))
You could change the return signature of the function and expect an array of an array with the factors and the product.
function factorize(number) {
if (number === 0 || number === 1) return [[1], 1];
var [factors, product] = factorize(number - 1);
return [[...factors, number], product * number];
}
console.log(factorize(5));
I was given this problem by my friend. The question asks to remove all the alphabetically consecutive characters from the string input given.
So I did it using Javascript, I need expert help if I performed it precisely.
I thought using Array.prototype.reduce will be the best way, do we have other possible ways?
/**
* #author Abhishek Mittal <abhishekmittaloffice#gmail.com>
* #description function can deal with both any types followed in a consecutive manner in ASCII Chart.
* #param {string} str
*/
function improvise(str) {
// Backup for original input.
const bck = str || '';
const bckArr = bck.split('').map( e => e.charCodeAt(0)); // converting the alphabets into its ASCII for simplicity and reducing the mayhem.
let result = bckArr.reduce( (acc, n) => {
// Setting up flag
let flag1 = n - acc.rand[acc.rand.length - 1];
let flag2 = n - acc.temp;
if(flag1 === 1 || flag2 === 1) {
(flag2 !== NaN && flag2 !== 1) ? acc.rand.pop() : null; // update the latest value with according to the case.
acc.temp = n
}else{
acc.rand.push(n); // updating the random to latest state.
acc.temp = null;
}
return acc;
}, {rand: [], temp: null} /* setting up accumulative situation of the desired result */)
result = result.rand.map(e => String.fromCharCode(e)).join('')
return result ? result : '' ;
}
function init() {
const str = "ab145c";
const final = improvise(str);
console.log(final)
}
init();
Well, the output is coming out to be correct.
Input: ab145c
Output: 1c
There's no way to solve this using any remotely reasonable regular expression, unfortunately.
I think it would be a lot clearer to use .filter, and check whether either the next character or the previous character is consecutive:
const code = char => char
? char.charCodeAt(0)
: -2; // will not be === to any other codes after addition or subtraction
function improvise(str) {
return [...str]
.filter((char, i) => {
const thisCode = code(char);
return (
thisCode !== code(str[i - 1]) + 1
&& thisCode !== code(str[i + 1]) - 1
);
})
.join('');
}
console.log(improvise('ab145c'));
(alternatively, you could check only whether the next character is consecutive, but then you'd have to check the validity of the last character in the string as well)
If you need continuously replace characters until no consecutive characters remain, then keep calling improvise:
const code = char => char
? char.charCodeAt(0)
: -2; // will not be === to any other codes after addition or subtraction
function improvise(str) {
return [...str]
.filter((char, i) => {
const thisCode = code(char);
return (
thisCode !== code(str[i - 1]) + 1
&& thisCode !== code(str[i + 1]) - 1
);
})
.join('');
}
let result = 'hishakmitalaaaaabbbbbbcccccclmnojqyz';
let same = false;
while (!same) {
const newResult = improvise(result);
if (newResult !== result) {
result = newResult;
console.log(result);
} else {
same = true;
}
}
console.log('FINAL:', result);
Well, that's great code but it doesn't gives the exact solution to the problem, see:
INPUT: hishakmitalaaaaabbbbbbcccccclmnojqyz
i got
Output: shakmitalaaaabbbbcccccjq
you see 'ab' & 'bc' remains intact, we need to increase the number of loops maybe to check those, can increase complexity as well.
But, my solution doesn't as well gives me the answer I desire e.g. for the above string I should get
ishakmitalaacccjq
but rather my solution gives
shakmitalcccccjq
hope you understand the question. We need a change in the way we traverse throughout the string.
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;
};