Over the course of learning any programming language you will inevitably run into loops. They are a foundational part of all computing and for the most part seem pretty straight forward. Today I thought we would take a look at a situation where things aren’t as straight forward and figuring out the loops might just drive you loopy (Ill be here all week :/).

Here are the problems:

Write a function called map2 that accepts two arrays and a function as arguments, and constructs a new array by invoking its function argument on the elements of both arrays, e.g.:

map2([1, 2, 3], [4, 5, 6], function(a, b) {
return a * b;
});
// => [4, 10, 18]

This first problem is fairly easy and straight forward but lets break it down so we know exactly where we are at.

function map2(array1, array2, fn) {
//first lets create the results array we are going to return 
var results = []; 

//create the normal for loop
for(var i=0; i<array1.length; i++) {
//inside the loop is where the magic happens
//notice we are pushing the results of calling fn on each item in the arrays simultaneously
results.push(fn(array1[i], array2[i]));

}
return results; 
}

Ok pretty easy. Now for the hard stuff…

Now, write a function called mapN that accepts an arbitrary number of arrays and a n-ary function as arguments, and constructs a new array by combining the elements of all the arrays, e.g.:

mapN([1, 2, 3], [4, 5, 6], [2, 2, 2], function(a, b, c) {
return (a * b) + c;
});
// => [6, 12, 20]

mapN([1, 2, 3], function(x) { return x * x; }) // => [1, 4, 9]

note: You’ll need to read about the arguments keyword and apply to complete this function.

Ok so lets again break this down…

function mapN () {
//This nifty piece of code uses the powers of call to manipulate the Array object into letting us slice the arguments array.
//Note that the arguments array isn't actually an array but is only array-like, meaning it doesn't come with the convenient 
//methods Arrays do. Using call we can tell the method exactly what to work on, in this case the arguments 'array'.
//We slice off all of the arguments except the last one knowing that it will be our function. This way we have now separated the 
//arrays from the function. 
var arrays = Array.prototype.slice.call(arguments, 0, arguments.length - 1);

//now lets create a simple variable to hold our function, again pulling it from the array-like arguments list. 
var fn = arguments[arguments.length - 1]; 

var results = []; 

//Ok this is where things get really sticky so stay with me...
//The first part of our loop we want to loop over the **first index** of each array so we make sure we call it with 
//the length of the first array within our arrays variable. (?very meta?)
for(var i=0; i<arrays[0].length; i++) {
//Now we need a place to temporarily store the reorganizing of our arrays
var tempArr = [];
//Now for the second loop we will make sure it is looping over each array, staying at whatever index the initial loop has us on
for(var j=0; j<arrays.length; j++) {
//Here we push each index of each array into our temp array essentially rearranging the pieces to the way we want them
tempArr.push(arrays[j][i]);
}
//Here is where the magic happens. We take and push the results of calling (in this case we use the apply method because we are using arrays) 
//our function on the temp array into the results array. 
results.push(fn.apply(null, tempArr));

}
return results;

}

Here is a simple visualization of what is happening:

// INPUT
[[1, 2, 3, 4], 
[4, 5, 6, 7], 
[7, 8, 9, 10]]

// INTERMEDIATE --> this where we do the rearranging, taking and matching each index from each array and putting them together. 
[[1, 4, 7],
[2, 5, 8],
[3, 6, 9],
[4, 7, 10]]

// RESULT

[12, 15, 18, 21]