How can i mix all of the arithmetical operators to finish my calculator - javascript

I had a calculator Project.I can multiply,add,divide and substract all the numbers in the input and get the result like output.
But i need help.How is the solution when the user
in same input wants first to substract,then divide then multiply and and etc. in this case.
A little explanation: I have the buttons with atribbutes and i added event listener when they are clicked they need to be showed on the screen.
After that i pushed them in array and then depen on the arithetic operation,,/,+,- i make search with reg ex and after that i remove them and i make the operation ab, a + b etc depending on that what includes the array when the = EQUAL BTN IS PRESSED. Can include *,/,+,- but in this case just one of that arithmetic operator.
const btns = document.querySelectorAll(".btn");
const screen = document.querySelector(".screen");
const equalBtn = document.querySelector(".btn-equal")
const clearBtn = document.querySelector(".btn-clear")
let get = []
for (let i = 0; i < btns.length; i++) {
btns[i].addEventListener("click", function() {
let number = btns[i].getAttribute("data-num");
screen.value += number;
get.push(number);
console.log(get);
})
}
equalBtn.addEventListener("click", function() {
if (get.includes("*")) {
const res = get.toString()
.match(/[^*]+/g)
.map(v => v.split(',')
.filter(v => v)
.map(v => +v))
var Multiply = res.map(function(el) {
return el.join('');
}).reduce(function(a, b) {
return a * b;
});
screen.value = Multiply;
}
if (get.includes("/")) {
const res = get.toString()
.match(/[^/]+/g)
.map(v => v.split(',')
.filter(v => v)
.map(v => +v))
var Divide = res.map(function(el) {
return el.join('');
}).reduce(function(a, b) {
return a / b;
});
screen.value = Divide;
}
if (get.includes("+")) {
const res = get.toString()
.match(/[^+]+/g)
.map(v => v.split(',')
.filter(v => v)
.map(v => +v))
var Adding = res.map(function(el) {
return el.join('');
}).reduce(function(a, b) {
return parseInt(a) + parseInt(b);
});
screen.value = Adding;
}
if (get.includes("-")) {
const res = get.toString()
.match(/[^-]+/g)
.map(v => v.split(',')
.filter(v => v)
.map(v => +v))
var Substracting = res.map(function(el) {
return el.join('');
}).reduce(function(a, b) {
return a - b;
});
screen.value = Substracting;
}
});
clearBtn.addEventListener("click", function() {
get.length = 0;
screen.value = "";
});

Related

Recursive Function - RangeError: Maximum call stack size exceeded - JavaScript

I'm trying to make a set of functions that add the digits of a number. But with giant numbers, the maximum amount of calls is exceeded. I would like to resolve this issue.
My code - (Example of error in calling the function at the end.):
const recursiveSum = (arr, iter) => {
let strNums = arr.reduce((acc, curr) => acc + curr, 0);
let arrNums = strNums.toString().split('').map(Number);
let res = arrNums.reduce((acc, curr) => acc + curr, 0);
let newArr = res.toString().split('');
const resLength = res.toString().split('').length;
if (iter === 0 || resLength === 1) {
return res;
} else {
return recursiveSum(newArr, iter - 1);
}
}
function getTheP(arr, k, p) {
console.log(k);
arr.map(num => {
p.push(num);
});
if (k === 0) {
return p;
} else {
getTheP(arr, --k, p);
}
}
function superDigit(n, k) {
let p;
const splitArr = n.toString().split('');
p = getTheP(splitArr, k, []);
const response = recursiveSum(p, k);
return console.log(response);
}
superDigit('4757362', 10000);

How to implement function composition in JavaScript?

Below are three functions that need to be composed and give us the output 30:
const add = (a) => a + 10;
const mul = (a) => a * 10;
const divide = (a) => a / 5;
// How to implement `compositionFunction`?
compositionFunction(add, mul, divide)(5);
//=> 30
Expected output is 30 because:
5 + 10 = 15
15 * 10 = 150
150 / 5 = 30
Something like this
const add = (a) => a + 10 ;
const mul = (a) => a * 10 ;
const divide = (a) => a / 5 ;
// How to use this function -----
const customComposeFn = (...f) => v => f.reduce((res, f) => f(res), v)
console.log(customComposeFn(add, mul, divide)(5));
There are two flavours of function composition:
left-to-right function composition aka pipe
right-to-left function composition aka compose
Here's a recursive implementation just for fun:
This assumes that there are at least two functions to compose
const compose = (...fn) => {
const [[f, g], x] = [fn.slice(-2), fn.slice(0, -2)];
const h = a => f(g(a));
return x.length ? compose(...x, h) : h;
}
const pipe = (...fn) => {
const [f, g, ...x] = fn;
const h = a => g(f(a));
return x.length ? pipe(h, ...x) : h;
}
Let's try:
const foo = x => x + 'foo';
const bar = x => x + 'bar';
const baz = x => x + 'baz';
pipe(foo, bar, baz)('');
//=> 'foobarbaz'
compose(foo, bar, baz)('');
//=> 'bazbarfoo'
const add = (a) => a + 10;
const mul = (a) => a * 10;
const divide = (a) => a / 5;
const customComposeFn = (...fn) => {
return function (arg) {
if (fn.length > 0) {
const output = fn[0](arg);
return customComposeFn(...fn.splice(1))(output);
} else {
return arg;
}
};
};
const res = customComposeFn(add, mul, divide)(5);
console.log(`res`, res);
Here's what I would do:
function customComposeFn(...funcs) {
return function(arg) {
let f, res = arg;
while (f = funcs.shift()) {
res = f(res)
}
return res;
}
}
const add = a => a + 10;
const mul = a => a * 10;
const divide = a => a / 5;
// How to use this function -----
console.log(customComposeFn(add, mul, divide)(5));

How could I find intersections in a string array with a variable number of elements?

I have a function that receives an array composed of numerical, comma separated strings as input, then finds the intersectional numbers in those strings and returns a string of similarly comma separated numbers, with no spaces, containing those intersections. If there are no intersections between the two elements, the function will return false.
What I want is to optimize the function so that it can work with a string array that may have more than just two elements. Is that possible? If so, could I have some sort of guideline of where to start looking for answers?
Currently, this is what I have.
function LocateIntersection(strArr) {
let arrHalf1 = strArr[0].split(", ");
let arrHalf2 = strArr[1].split(", ");
let interArr = arrHalf1.filter(value => arrHalf2.includes(value));
let result = interArr.join();
if (result) {
return result;
} else {
return false;
}
}
My answer is a little flawed, but it should meet your requirements
function LocateIntersection(strArr) {
const AllArrHalf = strArr.map((value) => value.split(', ')).sort((a, b) => b.length - a.length);
const lastArrHalf = AllArrHalf[AllArrHalf.length - 1];
let interArr = [];
AllArrHalf.forEach((value, index) => {
if (index !== AllArrHalf.length - 1) {
interArr.push(lastArrHalf.filter(value1 => value.includes(value1)))
}
})
if (interArr.length > 1) {
let result = interArr.map(value => value.join(', '));
LocateIntersection(result);
} else if (interArr.length === 1) {
result = interArr.join();
console.log(result);
}
}
LocateIntersection(['a, b, c', 'a, b', 'a, b'])
You can try this.
const intersection = (arr1, arr2) => {
return arr2.filter(element => arr1.includes(element));
}
const getIntersection = (stringArray, prevResult) => {
const array1 = prevResult || stringArray[0].split(', ');
const array2 = stringArray.shift().split(', ');
const result = intersection(array1, array2);
console.log(`result : `, result)
if(result.length > 0 && stringArray.length > 0) {
return getIntersection(stringArray, result);
}
return result;
}
const input = ['1, 2','1, 3, 3, 3','123, 222','1, 1, 1','1','3, 2, 3, 1'];
const result = getIntersection(input);
console.log('final Result:',result);

What's wrong with this combination-generating recursion?

I have the following code:
const findMult_3 = (num) => {
const powerset = (set) => {
const combinations = []
const combine = (prefix, chars) => {
for (let i = 0; i < chars.length; i++) {
combinations.push(prefix + chars[i])
combine(prefix + chars[i], chars.slice(i + 1))
}
}
combine('', set)
return combinations
}
const allCombinations = powerset(num.toString().split(''))
console.log(allCombinations)
}
findMult_3(362)
I would expect this to work, however, with the input of 362, the function console logs:
[ '3', '36', '362', '32', '6', '62', '2' ]
It's missing variants like 63, 23, 26 etc. It seems the slice call is to blame?
Still not 100% sure what the issue was with the slice call, but I fixed it by sidestepping the issue and avoiding mutating my arrays:
const findMult_3 = (num) => {
const powerset = (set) => {
const combinations = []
const combine = (prefix, chars) => {
for (let i = 0; i < chars.length; i++) {
combinations.push(prefix + chars[i])
combine(prefix + chars[i], chars.filter((x, ind) => ind !== i))
}
}
combine('', set)
return combinations
}
const allCombinations = powerset(num.toString().split(''))
console.log(allCombinations)
}
findMult_3(362)
Note the use of filter instead of splice, maintaining immutability.
I found the problem, duplicate the array (to c), and then remove the element you are combining with:
const findMult_3 = (num) => {
const powerset = (set) => {
const combinations = []
const combine = (prefix, chars) => {
console.log(chars);
for (let i = 0; i < chars.length; i++) {
combinations.push(prefix + chars[i])
var c = chars.slice();
c.splice(i,1);
combine(prefix + chars[i], c);
}
}
combine('', set)
return combinations
}
const allCombinations = powerset(num.toString().split(''));
console.log(allCombinations);

javascript least amount of elements from an integer array that can be used to get to a total value

please can somebody help?
If i have a total or a sum for instance 91
How can I create an array of the least amount of elements needed to get to the total value?
[50, 20, 10 , 5, 3, 2, 1] totaling this array will provide 91.
I know how to perform the opposite function using reduce or like so:
<script>
var numbers = [65, 44, 12, 4];
function getSum(total, num) {
return total + num;
}
function myFunction(item) {
document.getElementById("demo").innerHTML = numbers.reduce(getSum);
}
</script>
Greedy algorithm
Here is a solution using greedy algorithm. Note that this solution will work correctly in case when all the smaller numbers are divisors of all the bigger numbers such as in case [50, 10, 5, 1]. (see dynamic algorithm below this one for solution that can handle any input)
50 mod 10 = 0
50 mod 5 = 0
50 mod 1 = 0
10 mod 5 = 0
10 mod 1 = 0
5 mod 1 = 0
const sum = xs => xs.reduce((acc, v) => acc + v, 0);
function pickSubset(options, total, currentPick) {
if (sum(currentPick) === total) { return currentPick; }
if (options.length === 0) { return null; }
const firstVal = options[0];
let res = null;
if (sum(currentPick) + firstVal > total) {
res = pickSubset(options.slice(1), total, currentPick);
} else {
let opt1 = pickSubset(options, total, currentPick.concat(options[0]));
let opt2 = pickSubset(options.slice(1), total, currentPick.concat(options[0]));
if (opt1 && opt2) {
opt1.length < opt2.length ? res = opt1 : res = opt2
} else if (opt1) {
res = opt1;
} else {
res = opt2;
}
}
return res;
}
const total = 73;
const options = [50, 25, 10, 5, 2, 1];
console.log(pickSubset(options, total, []));
To handle unsorted input you can wrap it in another function and sort it prior to passing it to the main function.
const sum = xs => xs.reduce((acc, v) => acc + v, 0);
function pickSubset(options, total, currentPick) {
const sortedOptions = options.sort((a, b) => b - a);
function _pickSubset(options, total, currentPick) {
if (sum(currentPick) === total) { return currentPick; }
if (options.length === 0) { return null; }
const firstVal = options[0];
let res = null;
if (sum(currentPick) + firstVal > total) {
res = pickSubset(options.slice(1), total, currentPick);
} else {
let opt1 = pickSubset(options, total, currentPick.concat(options[0]));
let opt2 = pickSubset(options.slice(1), total, currentPick.concat(options[0]));
if (opt1 && opt2) {
opt1.length < opt2.length ? res = opt1 : res = opt2
} else if (opt1) {
res = opt1;
} else {
res = opt2;
}
}
return res;
}
return _pickSubset(sortedOptions, total, currentPick);
}
const total = 73;
const options = [50, 25, 10, 5, 2, 1].reverse();
console.log(pickSubset(options, total, []));
Dynamic programming (bottom-up natural ordering approach)
This solution works correctly for any type of input.
function pickSubset(options, total) {
function _pickSubset(options, change, minNums, numsUsed) {
for (let i = 0; i < change + 1; i++) {
let count = i;
let newNum = 1;
let arr = options.filter(v => v <= i);
for (let j of arr) {
if (minNums[i - j] + 1 < count) {
count = minNums[i - j] + 1;
newNum = j;
}
}
minNums[i] = count;
numsUsed[i] = newNum;
}
return minNums[change];
}
function printNums(numsUsed, change) {
const res = [];
let num = change;
while (num > 0) {
let thisNum = numsUsed[num];
res.push(thisNum);
num = num - thisNum;
}
return res;
}
const numsUsed = [];
const numsCount = [];
_pickSubset(options, total, numsCount, numsUsed);
return printNums(numsUsed, total);
}
const options = [50, 10, 5, 2, 1];
console.log(pickSubset(options, 73));
Dynamic programming (top-down memoization approach)
// helper function that generates all the possible solutions
// meaning, all the possible ways in which we can pay the provided amount
// and caches those solutions;
// returns the number of possible solutions but that is not neccessary
// in this case
const _pickSubset = (toPay, options, currentPick, cache) => {
if (toPay < 0) { return 0; }
if (toPay === 0) {
cache.add(currentPick);
return 1;
}
if (options.length === 0) { return 0; }
return _pickSubset(toPay - options[0], options, currentPick.concat(options[0]), cache)
+ _pickSubset(toPay, options.slice(1), currentPick, cache);
};
// memoize only with respect to the first two arguments - toPay, bills
// the other two are not necessary in this case
const memoizeFirstTwoArgs = fn => {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args.slice(0, 2));
if (cache.has(key)) { return cache.get(key); }
const res = fn(...args);
cache.set(key, res);
return res;
};
};
// uses memoized version of makeChange and provides cache to that function;
// after cache has been populated, by executing memoized version of makeChange,
// find the option with smallest length and return it
const pickSubset = (toPay, options) => {
const cache = new Set();
const memoizedPickSubset = memoizeFirstTwoArgs(_pickSubset);
memoizedPickSubset(toPay, options, [], cache);
let minLength = Infinity;
let resValues;
for (const value of cache) {
if (value.length < minLength) {
minLength = value.length;
resValues = value;
}
}
return resValues;
}
const options = [50, 25, 10, 5, 2, 1];
const toPay = 73;
console.log(pickSubset(toPay, options));

Categories