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.