Supporting arrays in custom functions with multiple inputs - javascript

I have a custom function in my google apps script that takes two variables. I want this function to take two arrays for parameters, but the standard approach of putting "if input.map, return input.map(function)" doesn't work with two variables.
I have tried recursing through the inputs, but since there are two in the function, it does not work with both.
this is not the function i am using, but it has the same problem.
function multiply(x,y)
{
if (x.map){
return x.map(multiply)
}
if (y.map){
return y.map(multiply)
}
return x * y
}
I expect the formula to take two arrays (i.e. A1:A5, B1:B5) and perform the function on each variable -- i.e. returning A1 * B1, A2 * B2 etc.

Issue:
multiply receives two arguments. When multiply is provided as a function argument to Array.map, the first argument will be the element of the array on which map is called and the second argument will be the element's index.
Solution:
Use map only on the first array x and then use elements from the corresponding second array y
Snippet:
function multiply(x, y) {
if (x.map) {
return x.map(function(xEl, i) {
yEl = y.map ? y[i] : y; // corresponding y Element
return multiply(xEl, yEl);
});
}
if (y.map) {//used, when y is a array and x is number
return multiply(y, x);
}
return x * y;// default
}
a = [[1],[2]];
b= [[3],[4]];
c= [[5,6],[7,8]];
d= [[1,2],[3,4]];
console.log(JSON.stringify(multiply(a,b)));
console.log(JSON.stringify(multiply(a,5)));
console.log(JSON.stringify(multiply(5,b)));
console.log(JSON.stringify(multiply(c,d)));
console.log(JSON.stringify(multiply(c,2)));
console.log(JSON.stringify(multiply(a,c))); //trims c
console.log(JSON.stringify(multiply(c,a)));//throws error
References:
Array#map

Related

How to use apply with currying?

I have code that is using currying to get the average on an array that results from concatenating two arrays: an n size array and an m size array.
var avg = function(...n){
let tot=0;
for(let i=0; i<n.length; i++){
tot += n[i];
}
return tot/n.length;
};
var spiceUp = function(fn, ...n){
return function(...m){
return fn.apply(this, n.concat(m));
}
};
var doAvg = spiceUp(avg, 1,2,3);
console.log(doAvg(4,5,6));
In this line return fn.apply(this, n.concat(m));, I don't understand why do we need to use apply. What is the object we are binding with the average function and why does just normal calling (return fn(n.concat(m));) not work?
In that example, this is not that important. It would also work if instead of this you would pass an empty object instead. It's just an example on how to use apply.
What you need to focus is on the second parameter n.concat(m). They key concept here is that passing an array as a second argument you are calling that function (fn) passing each value in the array as an argument.
About your second question: no, it won't work because fn expects several arguments (one per value to calculate the average) while by doing return fn(n.concat(m)); you are just passing one argument, an array containing all values
Maybe you would understand it better with a simpler example:
function sum3params(a,b,c){
return a+b+c;
}
console.log(sum3params([3,4,2])) // won't work
console.log(sum3params.apply(this, [3,4,2])) // will work ('this' is not important here)
For this use case, it does not. But consider the following:
var foo = {
bar: 3
};
var addBar = function(a, b) { return a + b + this.bar };
foo.add3AndBar = spiceUp(addBar, 3);
foo.add3AndBar(1); // 7
Using apply means that your spiceUp function can be applied to methods as well as normal functions. For more likely example, consider partially applying when defining a method on a prototype:
const ENV = "linux";
DoesSomePlatformSpecificStuff.prototype.getPath = spiceUp(ENV);
apply also will spread the gathered array of arguments back out into positional arguments which can also be done like so:
return fn(...n.concat(m));
Which can be simplified as
return fn(...n, ...m);
Which is equivalent to
return fn.apply(undefined, n.concat(m));

What is the meaning of "...args" (three dots) in a function definition?

It was really confusing for me to read this syntax in Javascript:
router.route('/:id')
.put((...args) => controller.update(...args))
.get((...args) => controller.findById(...args));
What does ...args mean?
With respect to (...args) =>, ...args is a rest parameter. It always has to be the last entry in the parameter list and it will be assigned an array that contains all arguments that haven't been assigned to previous parameters.
It's basically the replacement for the arguments object. Instead of writing
function max() {
var values = Array.prototype.slice.call(arguments, 0);
// ...
}
max(1,2,3);
you can write
function max(...value) {
// ...
}
max(1,2,3);
Also, since arrow functions don't have an arguments object, this is the only way to create variadic (arrow) functions.
As controller.update(...args), see What is the meaning of "foo(...arg)" (three dots in a function call)? .
Essentially, what's being done is this:
.put((a, b, c) => controller.update(a, b, c))
Of course, what if we want 4 parameters, or 5, or 6? We don't want to write a new version of the function for all possible quantities of parameters.
The spread operator (...) allows us to accept a variable number of arguments and store them in an array. We then use the spread operator again to pass them to the update function:
.put((...args) => controller.update(...args))
This is transparent to the update function, who receives them as normal arguments.
The meaning of “…args” (three dots) is Javascript spread operator.
function sum(x, y, z) {
return x + y + z;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers));
// expected output: 6
If you know some Python syntaxes, it is exactly the same as *args. Since *args (Python) is tuple object and Javascript has no tuple like Python, ..args is an Array object.
means pass all values (useful if have unknown# of items)
sample code
console.log(sum(1, 2, 3, 4)); // expected output: 10
function sum(...allItems) {
let total = 0;
for (const item of allItems) {
total += item;
}
return total;
}
It's called 'rest parameter', you can use rest parameter to pass unspecified number of arguments as an array, And a function can have only one rest parameter and it have to be the last parameter for the function
function sum(...args){
let output = 0;
for(const num of args){
output += num;
}
return output;
}
console.log(sum(2,4,8));
here it takes the argument that passed on sum as an array and sum the output and return it

Loop logic for drawing line javascript

I have following two arrays:
var element_1 = new Array([x1,y1],[x2,y2],[x3,y3],[x4,y4]);
var element_2 = new Array([x1,y1],[x2,y2],[x3,y3],[x4,y4]);
Logic:
I want to run a loop (nested) where each element of element_1 (for eg [x1,y1]) is compared to each element of element_2 and the shortest distance between them shall be calculated within the loop (I know how to calculate the shortest path). The tricky part here is that I need a reference that which pair made the shortest past and then obtain those [x1,y1] and [x2,y2] combinations to draw a line.
Sample data:
var element_1 = new Array([10,0],[20,10],[10,20],[0,10]);
var element_2 = new Array([10,30],[20,40],[10,50],[0,40]);
Line should be made between [10,20] and [10,30]. Also, I would somehow need to store the coordinates somewhere to pass it to the line drawing function
How can I do this? Any leads would be highly appreciated.
Here is how I would do it:
var element_1 = [[0,0],[1,2],[5,3],[6,8]];
var element_2 = [[0,1],[1,4],[5,9],[9,8]];
var closest = {a: false, b: false, distance: false};
for(var i=0; i<element_1.length; i++) {
for(var j=0; j<element_2.length; j++) {
var distance = calculate_distance(element_1[i], element_2[j]);
console.log('Distance between element_1['+i+'] and element_2['+j+']: ' + distance);
if(closest.distance === false || distance < closest.distance) {
closest = {a: element_1[i], b: element_2[j], distance: distance};
}
}
}
console.log('The shortest path is between '+closest.a+' and '+closest.b+', which is '+closest.distance);
function calculate_distance(a, b) {
var width = Math.abs( a[0] - b[0] ),
height = Math.abs( a[1] - b[1] ),
hypothenuse = Math.sqrt( width*width + height*height );
return hypothenuse;
}
As Roko C. Buljan said, in your case you can just replace new Array() with []. Here's why.
Well i liked this question a lot. It inspired me to invent a generic Array method to apply a callback with each other items of two arrays. So i called it Array.prototype.withEachOther(). What it does is exactly what #blex has done in his solution with nested for loops. It applies an operation (provided by the callback) to each array item with the other array's item. Let's see how it works.
Array.prototype.withEachOther = function(a,cb,s=0){
return this.reduce((p,et) => a.reduce((q,ea) => cb(et,ea,q),p),s);
};
var element_1 = [[10,0],[20,10],[10,20],[0,10]],
element_2 = [[10,30],[20,40],[10,50],[0,40]],
cb = (p1,p2,q) => {var h = Math.hypot(p1[0]-p2[0],p1[1]-p2[1]);
return h < q.d ? {d:h,p1:p1,p2:p2} : q},
minDist = element_1.withEachOther(element_2,cb,{d:Number.MAX_SAFE_INTEGER,p1:[],p2:[]});
console.log(minDist);
So let's explain what's going on.
Array.prototype.withEachOther = function(a,cb,s=0){
return this.reduce((p,et) => a.reduce((q,ea) => cb(et,ea,q),p),s);
};
is a reusable function. It will execute the operation that is provided in a callback function, with each other element of the two arrays. It takes 3 arguments (a,cb,s=0).
a is the second array that we will apply our callback to each item for each item of the array that is invoking .withEachOther.
cb is the callback. Below I will explain the callback applied specific for this problem .
s=0 is the initial (with a default value of 0) value that we will start with. It can be anything depending on the callback function.
return this.reduce((p,et) => a.reduce((q,ea) => cb(et,ea,q),p),s);
this part is the core of the function. As you see it has two nested reduces. The outer reduce has an initial value designated by the s, which is provided as explained above. The initial value gets initially assigned to the p argument of the outer reduce's callback and the other argument et is assigned one by one with each of the items of invoking array. (element of this). In the outer reduce we invoke another reduce (the inner reduce). The inner reduce starts with the initial value of the result of previous loop which is the p of outer reduce and after each calculation returns the result to it's reduced value variable q. q is our memory and tested in the callback to see if we keep it as it is or replace it with the result of our calculation. After inner reduce finishes a complete round it will return the q to p and the same mechanism will run again until we finish with all items of the array that's invoking .withEachOther.
cb = (p1,p2,q) => {var h = Math.hypot(p1[0]-p2[0],p1[1]-p2[1]);
return h < q.d ? {d:h,p1:p1,p2:p2} : q}
The callback is special to this problem. It will receive two points (each with x and y coordinates) Will calculate the distance between them and will compare it with the previously made calculation. If it's smaller it will replace q by returning this new value; if not it will return q as it is.

Javascript: Compose a function with argument placement instructions for each composition

I'm looking for a javascript function that can:
Condition (I)
compose another function when it does not have recursion in its definition, kind of like in maths when the function is given a power, but with multiple arguments possible in the first input - e.g. with a (math) function f:
f(x) := x+2
f5(x) = f(f(f(f(f(x))))) = x+10
Condition (II)
Or maybe even input custom arguments into each step of composition:
(52)2)2=
Math.pow(Math.pow(Math.pow(5,2),2),2) = Math.pow.pow([5,2],2,["r",2]])
//first arg set, how times the next, 2nd arg set - "r" stands for recursion -
//that argument will be occupied by the same function
//Using new solution:
_.supercompose(Math.pow,[[5,2],[_,2],[_,2]]) //-> 390625
2((52)3)=
Math.pow(2,Math.pow(Math.pow(5,2),3)) = Math.pow.pow([5,2],["r",2],["r",3],[2,"r"])
//Using new solution:
_.supercompose(Math.pow,[[5,2],[_,2],[_,3]]) //-> 244140625
_.supercompose(Math.pow,[[5,2],[_,2],[_,3],[2,_]]) //-> Infinity (bigger than the max. number)
Note: The above are just templates, the resulting function doesn't have to have the exact arguments, but the more close to this (or creative, for example, a possibility of branching off like this ->[2,4,"r",4,2,"r"], which would also be complicated) the better.
I've been attempting to do at least (I) with Function.prototype, I came up with this:
Object.defineProperty(Function.prototype,"pow",{writable:true});
//Just so the function not enumerable using a for-in loop (my habit)
function forceSlice(context,argsArr)
{returnArray.prototype.slice.apply(context,argsArr)}
Function.prototype.pow = function(power)
{
var args=power<2?forceSlice(arguments,[1]):
[this.pow.apply(this,[power-1].concat(forceSlice(arguments,[1])))];
return this.apply(0,args);
}
//Usage:
function square(a){return a*a;}
square.pow(4,2) //65536
function addThree(a,b){return a+(b||3); }
// gives a+b when b exists and isn't 0, else gives a+3
addThree.pow(3,5,4) //15 (((5+4)+3)+3)
Worst case, I might just go with eval, which I haven't figured out yet too. :/
Edit: Underscore.js, when played around with a bit, can fulfill both conditions.
I came up with this, which is close to done, but I can't get it to work:
_.partialApply = function(func,argList){_.partial.apply(_,[func].concat(argList))}
_.supercompose = function(func,instructions)
{
_.reduce(_.rest(instructions),function(memo,value)
{
return _.partialApply(_.partialApply(func, value),memo)();
},_.first(instructions))
}
//Usage:
_.supercompose(Math.pow,[[3,2],[_,2]]) //should be 81, instead throws "undefined is not a function"
Edit: jluckin's cleareance of terms (recursion-> function composition)
Edit: made example function return number instead of array
The term you are looking for is called function composition, not necessarily recursion. You can apply function composition in javascript easily since you can pass a function as an argument.
I created a small function called compose, which takes a function, an initial value, and the number of times to compose the function.
function compose(myFunction, initialValue, numberOfCompositions) {
if (numberOfCompositions === 1) {
return myFunction(initialValue);
}
else {
return compose(myFunction, myFunction(initialValue), --numberOfCompositions);
}
}
When this function is evaluated, you pass in some function f(x), some initial x0, and the repeat count. For example, numberOfCompositions = 3 gives f(f(f(x)));
If there is one composition, then f(x) is returned. If there are two compositions, compose returns f(x) with f(x) replacing x as the argument, with 1 passed in as the composition so it will evaluate f(f(x)).
This pattern holds for any number of compositions.
Since functions are treated as objects and can be passed as arguments of functions, this method basically wraps your "non-recursive" functions as recursive functions to allow composition.
Success(simplicity wins):
_.supercompose = function (func,instructions,context)
{
var val;
for(var i = 0; i < instructions.length; i++)
{
val = _.partial.apply(_,[func].concat(instructions[i])).apply(context||this,val?[val]:[]);
}
return val;
}
//Usage (with a function constructor for operations):
_.op = function(o){return Function.apply(this,"abcdefghijklmnopqrstuvwxyz".split("").concat(["return " + o]))}
_.op("a+b")(3,5) //-> 8
_.op("a*b")(3,5) //-> 15
_.supercompose(_.op("(a+b)*c*(d||1)"),[[1,2,3],[-5,_,1],[1,2,_,3]])
//-> (1+2)*((-5+((1+2)*3))*1)*3 -> 36

Unfamiliar use of square brackets in calling a function

In the middle of this page, I find the code below.
var plus = function(x,y){ return x + y };
var minus = function(x,y){ return x - y };
var operations = {
'+': plus,
'-': minus
};
var calculate = function(x, y, operation){
return operations[operation](x, y);
}
calculate(38, 4, '+');
calculate(47, 3, '-');
Now while I can trace how it works, I've never seen this use of square brackets before. It certainly doesn't look like it's creating an array or referencing a member of an array. Is this common? If so, where are some other examples?
It is a dictionary access, which is like an array, but with a key instead of a numeric index.
operations['+'] will evaluate to the function plus, which is then called with the arguments plus(x,y).
It's called bracket notation.
In JavaScript you can use it to access object properties.
here operations is an object where the symbols + and - refers to two functions.
operations[operation] will return a reference to function plus where value of operation is + and then the following () will invoke the function
operations is an object and when you do operations[property] you will get the associated function and then you are passing the operands as x and y.
operations['+'] is function (x,y){ return x + y } which is plus
operations['-'] is function (x,y){ return x - y } which is minus
My JavaScript book says that object properties need be named with arbitrary names. But '+' and '-' are not names. From the original question, it is inferred that object properties just need be keyed, not named.

Categories

Resources