When we work with data, we generally need to do something with it. Whether editing the data, sorting the data, transforming the data or some other task, we must be able to understand what the data is and what we want to do with it. One of the things we can do is altering the data and this is where a map function comes in. A map function takes in a collection and alters each item of the collection based on a provided mapper function.
In vanilla JavaScript, we could do the following to demonstrate this technique:
const purchases = [1.30, 20.40, 14.76];
function withTaxMapperFn(item) {
const withTax = item * 1.2;
return Math.round(withTax * 100) / 100;
}
const withTax = purchases.map(withTaxMapperFn);
console.log(withTax); // [1.56, 24.48, 17.71]
Our aim is to understand how the native map
function works and then to build our own implementation for it.
Tests
describe('map', () => {
it('should apply the callback correctly', () => {
const collection = [1, 2, 3];
const mapperFn = item => item * 2;
const actual = map(collection, mapperFn);
const result = [2, 4, 6];
expect(actual).toStrictEqual(result);
});
});
Realistically we just need to test that a given mapperFn
returns the correct results when passed alongside the collection and so I kept the test relatively simple. We have a collection and a mapper function that doubles each item in the collections, eventually returning a new collection that contains the doubled values as expected.
Implementation
The native map
function in javascript has the following signature:
let new_array = arr.map(function callback( currentValue[, index[, array]]) {
// return element for new_array
}[, thisArg])
Source: MDN Docs - Array.prototype.map()
In short we can provide a function which takes the current value, the index of that value in the collection and a reference to the collection itself. We will replicate this structure for our custom map function when we implement it. With that said, here is the implementation I have went with:
/**
* @function map
* @description A function to transform values of a collection
* @param {Array} collection - The collection to adapt
* @param {Function} mapperFn - The action to commit upon each item
* @returns {Array} A new array with the mapped results
*/
function map(collection, mapperFn) {
const output = [];
const clone = [...collection];
for (let index = 0; index < clone.length; index++) {
const altered = mapperFn(clone[index], index, clone);
output.push(altered);
}
return output;
}
Here we create the function map
. This function creates 2 internal arrays, one for the output and another as a clone
of the collection
. I create a clone so that if someone passes a mapper function that alters the array reference, the original collection
won't be altered, only the clone
. We then loop each item in the cloned array and call our mapperFn
providing the current item, the index of that item and a reference to the clone
array so as to match the JavaScript native map
signature outlined earlier in this article. Lastly we push the return value of the mapperFn
into the output
array and once the loop finishes, we return the output
array with the altered values.
Using our example of the native use case at the top of this article, we can implement the same code but use our custom map
function:
const purchases = [1.30, 20.40, 14.76];
function map(collection, mapperFn) {
const output = [];
const clone = [...collection];
for (let index = 0; index < clone.length; index++) {
const altered = mapperFn(clone[index], index, clone);
output.push(altered);
}
return output;
}
function withTaxMapperFn(item) {
const withTax = item * 1.2;
return Math.round(withTax * 100) / 100;
}
const withTax = map(purchases, withTaxMapperFn);
console.log(withTax); // [1.56, 24.48, 17.71]
Conclusions
Understanding how the tools that we use actually work is an important part of any craft and that goes no-less so for software engineering. Moving forward we will look at a couple of other commonly used array functions such as filter
, reduce
and sort
to gain a deeper understanding of what happens under the hood. Map is a function provided for arrays in most common languages, thus we began here to understand such implementations. We have much more to explore and hopefully this inspires you to try re-inventing the wheel for other things in your language of choice, to understand how it works!
Top comments (0)