Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mapping an array of functions over an array in Javascript

I often need to map a list of functions (processors) to several arrays(channels) of float data) so I have written a helper function...

const mapMany = function(processors, channels){
  processors.forEach( function(processor){
    channels = channels.map( (channel) => channel.map(processor) );
  });
  return channels;
};

This reads OK (to me at least!) but mapping an array of functions over another array seems like such a generic thing I can't help but wonder if it IS "a thing" already i.e. is there a better / built in / canonical way of implementing this "Map Many" type functionality and if so what is the proper name for it?

like image 872
Roger Heathcote Avatar asked Jan 24 '17 15:01

Roger Heathcote


People also ask

How do you map a function to an array?

The syntax for the map() method is as follows: arr. map(function(element, index, array){ }, this); The callback function() is called on each array element, and the map() method always passes the current element , the index of the current element, and the whole array object to it.

Can you map two arrays in JavaScript?

Approach: For this, we can create two arrays, in which one array contains the array elements that are to be mapped, and the second array stores all the return values of the corresponding function. We can use the JavaScript Array push() method to push the return values of the function in the output array.

Can you map an array JavaScript?

map() can be used to iterate through objects in an array and, in a similar fashion to traditional arrays, modify the content of each individual object and return a new array. This modification is done based on what is returned in the callback function.


2 Answers

Yes, there is a better approach for implementing this. Don't use forEach!

function mapMany(processors, channels) {
    return processors.reduce((channels, processor) =>
        channels.map(channel => channel.map(processor))
    , channels);
}

But no, there is no builtin for this nor a canonical name for it. It's a quite specific function, which can however be trivially composed of the standard building blocks.

like image 181
Bergi Avatar answered Oct 10 '22 12:10

Bergi


I think you are looking for compose. It looks something like this:

const compose = function (...fns) {
    const rest = fns.reverse();
    const first = rest.shift();
    return function (...args) {
        return rest.reduce((acc, f)=>f.call(this, acc), first.apply(this, args));
    };
};

Now you can compose functions like this:

const stringDouble = compose(String, x=>x*2);
stringDouble("44"); //==> "88"

["22","33","44"].map(stringDouble);
//=> ["44", "66", "88"]

And in your case you can write your function like this:

const mapMany = function(processors, channels){
  // compose iterates from last to first so i apply reverse
  const fun = compose.apply(undefined, processors.reverse());
  return channels.map(fun);
}; 

The advantage over your own code and the other answer using reduce is that this does not make processors.length arrays in the process but just the one.

There are libraries that supplies compose. It's a common function in functional programming.

Other mapping functions like the ones in Underscore lets you set this. Then class methods will work as I pass this to the underlying functions as well.

like image 37
Sylwester Avatar answered Oct 10 '22 13:10

Sylwester