Categories
Lodash

Learning JavaScript by Implementing Lodash Methods — Flattening and Mapping

Spread the love

Lodash is a very useful utility library that lets us work with objects and arrays easily.

However, now that the JavaScript standard library is catching up to libraries such as Lodash, we can implement many of the functions in simple ways.

In this article, we’ll look at how to create our own methods to flatten collections.

flatMap

The Lodash flatMap method runs an iteratee function on each array entry of the original array and then flattens the resulting array and returns it.

We can implement it as follows:

const flatMap = (arr, iteratee) => arr.map(iteratee).flat()

In the code above, we called the map method on arr to map each entry to iteratee then called flat to flatten the resulting array.

Then when we call our flatMap function as follows:

const result = flatMap([1, 2], a => [a, a]);

We get that result is [1, 1, 2, 2] .

flatMapDeep

Lodash’s flatMapDeep method is like flatMap , but recursively flattens the resulting array.

We can implement this as we did with the flatMap method as follows:

const flatMapDeep = (arr, iteratee) => arr.map(iteratee).flat(Infinity)

The only difference between our flatMapDeep and flatMap method is that we passed in Infinity to flat to recursively flatten our resulting array after mapping each entry by calling iteratee .

Then when we can it as follows:

const result = flatMapDeep([1, 2], a => [[a, a]]);

result should be [1, 1, 2, 2] .

flatMapDepth

The flatMapDepth is like flatMap but we can specify the depth of the flattening of the resulting array.

The plain JS flat method also accepts the depth of the flatten as an argument, so we can just use that again:

const flatMapDepth = (arr, iteratee, depth) => arr.map(iteratee).flat(depth)

Then when we call it as follows:

const result = flatMapDepth([1, 2], a => [
  [a, a]
], 1);

We get:

[
  [
    1,
    1
  ],
  [
    2,
    2
  ]
]

as the value of result since we specified that the depth is 1.

groupBy

The groupBy method returns an object that takes the items in an array, calls an iteratee function and add that as the key of the returned object].

Then it creates an array as the value for each key, and then push the items that are the same as the key when iteratee is called with it into the array.

We can implement that as follows:

const groupBy = (arr, iteratee) => {
  let obj = {};
  for (const a of arr) {
    if (!Array.isArray(iteratee(a))) {
      obj[iteratee(a)] = [];
    }
    obj[iteratee(a)].push(a);
  }
  return obj;
}

In the code above, we looped through the items with a for...of loop, then populate the keys by calling iteratee on an array entry and then add the key with the empty array as the value.

Then when push the items into the array of the corresponding key.

Then when we call it as follows:

const result = groupBy([6.1, 4.2, 6.3], Math.floor);

We get that result is:

{
  "4": [
    4.2
  ],
  "6": [
    6.3
  ]
}

includes

The Lodash includes method checks if an item is in the collection. It also takes a starting index to start searching for.

We can implement this with the slice and includes method as follows:

const includes = (arr, value, start) => arr.slice(start).includes(value)

In the code above, we called slice on arr to start the search from the start index. Then we call array instance’s includes method to check if the item is in the sliced array.

Then when we call it as follows:

const result = includes([6.1, 4.2, 6.3], 6.3, 1);

result should be true since 6.3 is in the part of the array that has an index bigger than or equal to 1.

invokeMap

The Lodash invokeMap method maps the values of an array and returns it according to what we pass in as the argument.

Lodash invokeMap takes a string with the function name or a function to invoke on each collection entry. It also takes an argument for arguments.

We can implement it as follows:

const invokeMap = (arr, fn, ...args) => arr.map(a => fn.apply(a, args))

In the code above, we used the rest operator to spread the args into an array. Then we called map on arr to map each entry by calling apply on fn to map the values with the specified function.

We kept it simple by only assuming that fn is a function, unlike the Lodash version.

Then when we call invokeMap as follows:

const result = invokeMap([123, 456], String.prototype.split, '')

We get that result is:

[
  [
    "1",
    "2",
    "3"
  ],
  [
    "4",
    "5",
    "6"
  ]
]

since we split the number into substrings.

Conclusion

The flatMap family methods can be implemented with the map and flat methods.

To implement the groupBy method, we just have to populate an object by calling the iteratee function on each array entry and then populating them as keys. The values will be the original values that return the same value as the key when we call iteratee on it.

We can use plain JavaScript’s includes method to implement our own Lodash’s includes .

Finally, invokeMap can be implemented by using the rest operator to spread the arguments into an array and then use apply to call the passed-in function on each entry.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *