(This post first appeared on my personal blog)
Recently, I decided it would be a good idea to recreate some of the functions used in the popular JavaScript utility library Lodash to test my understanding of JavaScript and also practice writing unit tests in Jest.
For anyone unfamiliar with Lodash, it is a library that allows you to drop in various helper functions for performing common transformations.
In most instances, it is better to use a library like Lodash over rolling your own implementations for these methods because the functions included
in these libraries are extremely performant and have been tested in many different browsers and use cases. However, for educational purposes, I think it is a good idea to solve these problems since a library as popular as Lodash wouldn't be created to solve these problems otherwise.
I decided to start with the array methods and work my way down the list. Here is the description of the chunk utility function from the documentation:
Creates an array of elements split into groups the length of size. If array can't be split evenly, the final chunk will be the remaining elements.
Let's restate the problem to be sure that we understand it. The chunk function will return an array of elements or 'groups'; these groups will be arrays and each group will contain as many elements as determined by the size argument passed into the function. In the event of leftover elements, the leftover elements will be placed into the final array. The documentation also states that if a size value is not provided, a default value of 1 will be applied for the size. Below is an example of what we wish to accomplish.
chunk(['a', 'b', 'c', 'd'], 2);
// => [['a', 'b'], ['c', 'd']]
We know that we will need an array to store the groups, so let's create a function expression chunk and declare a variable chunkedValues
and assign it to an empty array.
const chunk = (array, size = 1) => {
let chunkedValues = [];
}
Notice the use of the default parameter.
Next, let's think about how we might group values before pushing them into an array. If we loop through the given array, and instead of incrementing by one each time, we incremented by the size argument, we would effectively start at the beginning of each group. Considering the example above, if we loop through the array and increment each time by 2 (the size), on the first loop we would start at the virst value, on the second loop, the index would point to value 'c', which is the start of the next and final group. To collect the groups, we can use the slice method which returns a copy of the array
from the index given up to an end index (the end index is not included in the array). In other words, at the first item in the array (index 0), we would slice from 0 to 2 (0 + 2), which would return the array ['a', 'b']
since the slice doesn't include index 2 in the final result. Below is the final code for reference.
const chunk = (array, size = 1) => {
let chunkedValues = [];
for (let i = 0; i < array.length; i += size) {
chunkedValues.push(array.slice(i, i + size));
}
return chunkedValues;
};
If the slice method isn't clicking at the moment, let's consider what the slice method is doing in this function by recreating it. By using the slice method, we are (in effect) creating a new array within the initial
for loop at each iteration (denoted by group in the code below) and then using an inner for loop to collect and push each of the values for this particular group. When the inner for loop terminates, we push group array into the chunkedValues
array. I've provided some example code below to illustrate this concept:
const chunk = (array, size = 1) => {
let chunkedValues = [];
for (let i = 0; i < array.length; i += size) {
let group = [];
// prevents the loop from adding undefined values in the group array
let length = i + size > array.length ? array.length : i + size;
for (let j = i; j < length; j++) {
group.push(array[j]);
}
chunkedValues.push(group);
}
return chunkedValues;
};
One thing to notice in the implementation above is the length variable. When using the slice method, if the end value provided to the method is greater than the length of the array, the method only takes the values up to and including the last item in the array. The logic in the length variable handles this case since it checks if the index plus the size argument is greater than the length of the array. If it is greater than the length of the array, then we assign it the value of the length of the array, otherwise we assign it to the index + the size argument.
I hope this article encourages you to look into Lodash and implement some of the functions yourself (and remember, this is only one implementation of this function, and certainly not the best or most performant solution). If you want to take a look at my github repo with the test cases, you can check it out here. If you have any comments, questions, or suggestions, please let me know!
Top comments (0)