Variable containing an operator in Javascript - javascript

I'm trying to make a change to a variable using a custom operator (I will explain it clearlier now).
I have an array of numbers, and I have to reduce() it. First 2 numbers will be added, then in the second reducing they will be substracted, then multiplied, divided and exponentiated. Basically:
[1,2,3,4,5] -> 0
1+2=3
3-3=0
0*4=0
0/5=0 -> 0
So I saw an implementation like this:
f => f.reduce((a,b,c) => [a + b, a - b, a * b, a / b, a ** b][c % 5])
And wondered, can I make an array of operators in some way, and implement it like this?
f => f.reduce((a,b,c) => a [+,-,*,/,**][c%5] b)
Clearly this syntax is incorrect, but in the terms of an idea, does something like this exist?

You can use eval() method
var f = [1, 2, 3, 4, 5];
console.log(
f.reduce((a, b, c) => eval(a + ['+', '-', '*', '/'][c-1] + b))
);
Also I don't prefer to use eval(), refer : Don't use eval needlessly!
UPDATE :
Also as #NinaScholz said, you can reduce the code by using string instead of string array. Both string and array have same effect in this case.
var f = [1, 2, 3, 4, 5];
console.log(
f.reduce((a, b, c) => eval(a + '+-*/'[c - 1] + b))
);

You can try something like this
var add = function(a, b) {
return a + b;
},
sub = function(a, b) {
return a - b;
},
mul = function(a, b) {
return a * b;
},
div = function(a, b) {
return a / b;
};
var operations = [add, sub, mul, div];
var output = [1, 2, 3, 4, 5].reduce(function(p, c, i) {
return operations[i - 1](p, c)
});
console.log(output);
You can add more functions (custom operators) and decide the order of operations.

You could use an array for the operators.
var array = [1, 2, 3, 4, 5],
op = [
(a, b) => a + b,
(a, b) => a - b,
(a, b) => a * b,
(a, b) => a / b,
];
console.log(array.reduce((r, a, i) => op[(i - 1) % 4](r, a)));

Related

When using using reduce with ternary inside a map, I seem to have troubles

this is to return an array of numbers that are the highest value of the arrays inside of the base array. I can get it to work when i use for statements. But I have tried to simplify it, and can't work out why it doesn't work. any help would be appriciated.
function largestOfFour(arr) {
return arr.map((x) => x.reduce((a, c) => c > a ? c : a, 0));
}
Example with input and output:
const input = [
[1,2,3,4,5],
[6,5,4,3,2,1],
[1,7,3,4,5,6],
];
function findHighestElements(arr) {
return arr.map((x) => x.reduce((a, c) => c > a ? c : a, 0));
}
console.log(findHighestElements(input)); // [5,6,7]
You don't need to reduce, you can do it by just Math.max. like this:
function findMaxNumbers(arr) {
return arr.map((x) => Math.max(...x));
}
let test = [[1, 2, 3],[4, 5, 6],[7, 8, 9]];
console.log(findMaxNumbers(test));
If you have values smaller than zero, you need to remove the start value
x.reduce((a, c) => c > a ? c : a, 0)
^
or use a very small start value, like -Number.MAX_VALUE.
To get the max of all the maxes, you can reduce the reductions. If you just want the max's, map the reduction.
const maxOfArray = a => a.reduce((a, c) => c > a ? c : a, -Number.MAX_SAFE_INTEGER); // thanks to Nina
const conciseVLAZMax = a => Math.max(...a); // thanks to VLAZ
let a = [
[1, 2, 3],
[6, -1, -2],
[3, 4, 5],
]
let maxs = a.map(maxOfArray);
let maxMax = maxOfArray(maxs);
console.log(maxs);
console.log(maxMax);

Return multiple values from function in an assigment

If I want to return a multiple values from a function, in an assigment, do I need to use an intermediate array to receive those values?
How am I used to do it in JavaScript:
let f = () => return [1, 2, 3];
let a, b, c, arr;
arr = f();
a = arr[0]; b = arr[1]; c = arr[2]
Is JavaScript like C, returning assignment to the first lhand operator, or is it possible to do something more flexible, like in this example from Ruby (without using loop):
def f
return 1, 2, 3
end
a, b, c = f
My motivation is simply lack of readability in the JavaScript method.
Issues
return not needed in simple arrow function
destructure assignment syntax
let f = () => [1, 2, 3];
let [a, b, c] = f();
console.log(a, b, c)
You can get values from an array either using index or using destructuring . If there are multiple values then you can easily destructure and store it in different variables in a single statement.
let f = () => [1, 2, 3];
//Using Destructuring
const [a, b, c] = f();
console.log(a, b, c);
// Accessing using index
const arr = f();
const m = arr[0];
const n = arr[1];
const o = arr[2];
console.log(m, n, o);
Since you are using an array to return multiple values then you can use either implicitly return in a function of you can explicitly return an array from it
1) Explicitly return
let f = () => {
return [1, 2, 3];
};
const [a, b, c] = f();
console.log(a, b, c);
2) Implicitly return
let f = () => [1, 2, 3];
const [a, b, c] = f();
console.log(a, b, c);

Find average of each array within an array

I'm trying to write a map/reduce to get the average of each array within an array.
For example.
[[1][2,3][4,5,6,7]] => [1, 2.5, 5.5]
Right now this is my code where result is the array of arrays:
result.map(array => {
return array.reduce((a, b) => (a + b)) / array.length;
})
const result = [
[1],
[2, 3],
[4, 5, 6, 7]
]
console.log(result.map(array => {
return array.reduce((a, b) => (a + b)) / array.length;
}))
Any help to get the desired output is much appreciated. As it stands, my output is reducing to an array of NaN's instead of the averages.
You need a closing parentesis.
By using Array#reduce with arrays with unknown length, you need to take a start value, which is in this case of a length of zero the result.
var result = [[1], [2, 3], [4, 5, 6, 7]],
avg = result.map(array => array.reduce((a, b) => a + b, 0) / array.length);
// ^^^ ^
// optional required
console.log(avg);
you must provide a second argument to the reduce function, the initial value of a. So:
result.map(array => {
return array.reduce((a, b) => a + b, 0) / array.length;
});
You may also want to ensure that array.length > 0 before you divide by it

Recognise operator and perform calculation

I have this problem:
Write a simple interpreter which understands "+", "-", and "*" operations. Apply the operations in order
using command/arg pairs starting with the initial value of value. If you encounter an unknown command, return -1. You are to ignore B.O.D.M.A.S completely.
Examples of the input and output
interpret(1, ["+"], [1]) → 2
interpret(4, ["-"], [2]) → 2
interpret(1, ["+", "*"], [1, 3]) → 6
interpret(5, ["+", "*", "-"], [4, 1, 3]) → 6
I have tried passing the parameters as multidimensional arrays below. I am trying to solve the problem such that when I do this
let operator = ["+", "-"];
let integer = 1;
let intArr = [1, 2];
let emptyInt;
let anotherInt;
let newArray = [integer, operator, intArr];
How do I make this work like above? Adding each of the array sequentially
you can do that using Array.prototype.reduce().ac to first value. And then add/minus/divide/multiply by by checking the operator.
function interpret(...args){
let operators = args[1]; //get the operators array
let values = args[2] //numbers expect the first one.
return values.reduce((ac,val,i) =>{
//check the operator at the 'i' on which we are on while iterating through 'value'
if(operators[i] === '+') return ac + val;
else if(operators[i] === '-') return ac - val;
else if(operators[i] === '*') return ac * val;
else if(operators[i] === '/') return ac / val;
else return -1;
},args[0]) //'ac' is initially set to first value.
}
console.log(interpret(1, ["+"], [1]))
console.log(interpret(4, ["-"], [2]))
console.log(interpret(1, ["+", "*"], [1, 3]))
console.log(interpret(5, ["+", "*", "-"], [4, 1, 3]))
You could use a recursive approach. Firstly, you can define an object to map your operators to useable functions, and then call a recursive function to calculate your result:
const oper = {
'+': (a, b) => a + b,
'-': (a, b) => a - b,
'*': (a, b) => a * b,
'/': (a, b) => a / b
};
const interpret = (n, [fc, ...calcs], [fn, ...nums]) =>
fc === undefined ? n :
interpret(oper[fc](n, fn), calcs, nums)
console.log(interpret(1, ["+"], [1])); // 2
console.log(interpret(4, ["-"], [2])); // 2
console.log(interpret(1, ["+", "*"], [1, 3])); // 6
console.log(interpret(5, ["+", "*", "-"], [4, 1, 3])); // 6
If returning -1 for invalid operands is a must you can use the following:
const oper = {
'+': (a, b) => a + b,
'-': (a, b) => a - b,
'*': (a, b) => a * b,
'/': (a, b) => a / b
};
const interpret = (n, [fc, ...calcs], [fn, ...nums]) => {
if(fc === undefined) return n;
if(!(fc in oper)) return -1;
return interpret(oper[fc](n, fn), calcs, nums)
}
console.log(interpret(1, ["+"], [1])); // 2
console.log(interpret(4, ["-"], [2])); // 2
console.log(interpret(1, ["+", "*"], [1, 3])); // 6
console.log(interpret(5, ["+", "*", "-"], [4, 1, 3])); // 6
console.log(interpret(1, ["+", "%"], [1, 2])); // -1
You could take an object with the needed functions for the operators and redue the array by taking the value and an operand.
const
fns = {
'+': (a, b) => a + b,
'-': (a, b) => a - b,
'*': (a, b) => a * b,
'/': (a, b) => a / b
},
interpret = (start, operators, values) =>
values.reduce(
(a, b, i) => operators[i] in fns
? fns[operators[i]](a, b)
: - 1,
start
);
console.log(interpret(1, ["+"], [1])); // 2
console.log(interpret(4, ["-"], [2])); // 2
console.log(interpret(1, ["+", "*"], [1, 3])); // 6
console.log(interpret(5, ["+", "*", "-"], [4, 1, 3])); // 6
You can do this way:--
function getOperator(number, operator, integer) {
let result;
switch (operator) {
case '+':
result = number + integer;
break;
case '-':
result = number - integer;
break;
case '*':
result = number * integer;
break;
case '/':
result = number / integer;
break;
}
return result;
}
function doOperation(array) {
number = array[0];
for (let i = 0; i < array[1].length; i++) {
number = getOperator(number, array[1][i], array[2][i]);
}
return number;
}
You can then use this to achieve asked :--
doOperation([1, ["+"], [1]])

Why wont my calculator function complete the math?

Hi so I'm having trouble figuring out why my function will do the division but leave the multiplication as an array without completing the math. Here's the code:
const mathObj = {
"*": function(a , b) {return a * b},
"/": function(a , b) {return a / b},
"+": function(a , b) {return a + b},
"-": function(a , b) {return a - b}
}
const arr = [ 10, "/" , 2 , "*" , 10 , "/" , 2 ];
function solveTheMath(arr) {
const len = arr.length;
for(let i = 0 ; i < len ; i++){
if(arr[i] === "/" || arr[i] === "*"){
const sliced = arr.slice(i - 1 , i + 2);
var mathResult = mathObj[arr[i]](sliced[0], sliced[2]);
arr.splice(i - 1 , 3, mathResult);
console.log(arr);
//[5*5]
}
}
}
solveTheMath(arr);
Why doesn't the multiplication work but the division does?
My initial answer, while it did solve the issue, wasn't that correct. You wanted to use an iterative approach by the look of things (i.e. using a loop to navigate through the initial array and solve all operations before returning the result).
So I replied to you:
Both operations work, the problem is that you're only calling solveTheMath once.
You need to call your function again to solve the array you have constructed. If the constructed array is made of only one element that means the process has reached the end of the computing, you can, therefore, return the first (and only element) of the array.
You are solving the problem in a recursive manner:
const mathObj = {
"*": function(a , b) {return a * b},
"/": function(a , b) {return a / b},
"+": function(a , b) {return a + b},
"-": function(a , b) {return a - b}
}
const arr = [ 10, "/" , 2 , "*" , 10 , "/" , 2 ];
function solveTheMath(arr) {
const len = arr.length;
for(let i = 0 ; i < len ; i++){
if(arr[i] === "/" || arr[i] === "*"){
const sliced = arr.slice(i - 1 , i + 2);
var mathResult = mathObj[arr[i]](sliced[0], sliced[2]);
arr.splice(i - 1 , 3, mathResult);
if(arr.length == 1) {
return arr[0]; // <- no more calculations needed, return result
} else {
return solveTheMath(arr); // <- more calculations needed, call it again
};
}
}
}
console.log(solveTheMath(arr))
But actually that isn't correct, you can use both approaches: recursive and iterative to solve this problem. My initial answer provided a poor solution: I kept your for loop and called the function again to solve the remaining operations that were in the array. That wasn't necessary because the for loop only looped to find the second item and stopped. Anyway, here's a clearer answer, highlighting both approaches.
Note: I have renamed solveTheMath to calculate and mathObj to operations.
Iterative approach
That's the approach you went for with your question. Because you are using a for loop to calculate all operations on a single function call (so the function isn't calling itself over and over).
I recommend using a while loop for this because **you will have a hard time looping arr when it gets modified (you are replacing three elements with one on each loop).
I'll take the array [10, "/", 2, "*", 10, "/", 2] as the starting array to show the process step by step. You can solve the first operation of the provided array. For example, given: , calculate will calculate the first operation here: 10, "/", 2
While the array contains more than one element we will do the following:
the first three elements of the array contain: two factors and an operator sign. By slicing the array we can extract those values and save them. I'm using a destructuring assignment to make it more verbose:
const [a, operator, b] = arr.slice(0, 3);
here a = 10, operator = "/" and b = 2
we will calculate the result of this operation with this line:
const result = operations[operator](a, b);
result = 5 (cf: 10 / 2)
then replace the first three elements of the array with the integer result:
arr.splice(0, 3, result);
at this point, arr is equal to [5, "*", 10, "/", 2]
The block has been executed, the while condition is checked again. arr does contain more than one element so the block is executed again. Remember, at this point arr is equal to [5, "*", 10, "/", 2], not to [10, "/", 2, "*", 10, "/", 2] (we are making progress in the calculation).
At the end of the second loop we have arr that is equal to [50, "/", 2].
A loop after that it is equal to [25].
The while condition isn't met anymore because arr only contains one element, the while loop has stopped and the result can be returned.
const operations = {
"*": (a, b) => a * b,
"/": (a, b) => a / b,
"+": (a, b) => a + b,
"-": (a, b) => a - b
}
const calculate = arr => {
while(arr.length > 1) { // <- while there are calculations to be done, repeat this block
const [a, operator, b] = arr.slice(0, 3);
const result = operations[operator](a, b);
arr.splice(0, 3, result);
}
return arr[0]; // <- no more operations to be done, return result
}
console.log(calculate(
[10, "/", 2, "*", 10, "/", 2]
));
Recursive approach
We can use a recursive approach: the function will only calculate the first operation of the provided array and return a new array with the result of this first operation.
Here is an example:
Same as in the iterative array, given the input [10, "/", 2, "*", 10, "/", 2] we will first take the first two factors and operator sign by slicing the array. Then we will calculate the result of the operation. Finally, we'll replace the first three elements of the array with this result:
const [a, operator, b] = arr.slice(0, 3);
const result = operations[operator](a, b);
arr.splice(0, 3, result);
then we check the length of this array:
if it contains only one element, it can be returned
else if it doesn't (in our case) we call the function again (this time on [5, "*", 10, "/", 2]).
So the function runs again with a new input and arr becomes [50, "/", 2] which has more than one element so the function needs to be called again (with [50, "/", 2] as input)
Now, arr is [25] it only contains one element, the result can be returned (25).
const operations = {
"*": (a, b) => a * b,
"/": (a, b) => a / b,
"+": (a, b) => a + b,
"-": (a, b) => a - b
}
const calculate = arr => {
const [a, operator, b] = arr.slice(0, 3);
const result = operations[operator](a, b);
arr.splice(0, 3, result);
if (arr.length == 1) {
return arr[0]; // <- no more calculations needed, return result
} else {
return calculate(arr); // <- more calculations needed, call it again
}
}
console.log(calculate(
[10, "/", 2, "*", 10, "/", 2]
));
Going further...
You can see both methods are quite similar: the main process is the same but the way they handle the end of execution is different. In this case, both are reasonable to use. The iterative approach may seem more natural to you at first. However remember that recursion can allow you to solve more complicated problems. For example, if you would like to implement a kind parenthesis system in your function:
How would you go about calculating: 10*(2+2)/2? calculate([10, "*", 2, "+", 2, "/", 2]) would obviously return 11...
Take the input [[10, "+", 2], "/", 2] instead, that makes more sense! How can we calculate the correct result?
Well with our recursive approach this can be implemented quite easily: if a or/and b are arrays then we reassign them by calling calculate on them. That's all:
if(a.constructor == Array) {
a = calculate(a);
}
if(b.constructor == Array) {
b = calculate(b);
}
const operations = {
"*": (a, b) => a * b,
"/": (a, b) => a / b,
"+": (a, b) => a + b,
"-": (a, b) => a - b
}
const calculate = arr => {
let [a, operator, b] = arr.slice(0, 3);
if(a.constructor == Array) {
a = calculate(a);
}
if(b.constructor == Array) {
b = calculate(b);
}
const result = operations[operator](a, b);
arr.splice(0, 3, result);
if (arr.length == 1) {
return arr[0]; // <- no more calculations needed, return result
} else {
return calculate(arr); // <- more calculations needed, call it again
}
}
console.log(calculate(
[[10, "+", 2], "/", 2]
));
Adding those two if blocks in the while loop of the iterative approach would have worked. But then you would be left with a... recursive function. That's why you may want to go straight off with the recursive approach. That allows you to expand your code more easily.
More reference on recursion
Recursion in JavaScript, freecodecamp.org
How factorial's recursive implementation works, wikimedia
Understanding recursive functions in JavaScript, medium.com
Scope and the function stack: recursion, MDN web docs

Categories