DEV Community

James Robb
James Robb

Posted on • Edited on

Array map

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]
Enter fullscreen mode Exit fullscreen mode

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);
  });
});
Enter fullscreen mode Exit fullscreen mode

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])
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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)