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 replace the takeWhile
, union
, unionBy
and unionWith
with plain JavaScript code.
takeWhile
takeWhile
is a reverse of takeRightWhile
. It returns the slice of an array with elements taken from the beginning until the predicate
function with the given array entry returns true
.
We can easily implement this ourselves with slice
as follows:
const takeWhile = (arr, predicate) => {
let takenArr = [];
for (const a of arr) {
if (!predicate(a)) {
takenArr.push(a);
} else {
return takenArr;
}
}
return takenArr;
}
In the code above, we used the for...of
loop to loop through the entries and returns takenArr
if predicate(a)
returns true
.
We also return takenArr
if the loop finishes if predicate(a)
never returns true
.
Then when we call it as follows:
const result = takeWhile([30, 40, 50], a => a > 40);
We get that result
is [30, 40]
since we specified we stop if an element if bigger than 40.
union
The union
method returns a new array with unique values from multiple arrays in order using the SameValueZero equality comparison.
We can implement it ourselves with the spread operator as follows:
const union = (...arrs) => {
return arrs.reduce((arr1, arr2) => [...new Set([...arr1, ...arr2])])
}
In the code above, we called reduce
on arrs
with a callback that returns the unique values of the 2 arrays spread with spread operator. The new array is then converted to a set and then converted back to an array with the spread operator.
Then we can call it as follows:
const result = union([30, 40, 50], [30, 60]);
and result
is [30, 40, 50, 60]
since the values from the earlier arrays are kept and then the later ones that aren’t already in the accumulated array is added.
unionBy
The unionBy
method returns an array with the unique items in each array. The difference between this and union
is that unionBy
lets us pass in a method to map the values before doing the uniqueness comparison.
We can implement it as follows:
const unionBy = (iteratee, ...arrs) => {
let unionArr = [];
for (const arr of arrs) {
const mapped = arr.map(iteratee);
const unionMapped = unionArr.map(iteratee);
const uniques = mapped.filter(a => !unionMapped.includes(a));
unionArr = [...unionArr, ...uniques];
}
return unionArr;
}
In the code above, we have the iteratee
as the first argument instead of the last so that we can use the rest operator with arrs
to return an array of the array arguments passed in after the iteratee
function.
Then we have a for...of
loop to loop through the items and inside the loop, we map the arr
entries with the iteratee
function.
Also, we mapped the unionArr
array with the same function so that we can use the includes
method with filter
to get the entries that aren’t unionArr
yet after comparing it after converting the values with iteratee
.
Then when we call it as follows:
const result = unionBy(Math.floor, [30.1, 40, 50], [30.2, 60]);
We get [30, 40, 50, 60]
for result
since we mapped the values in all arrays with Math.floor
before doing a comparison.
unionWith
unionWith
is like union
except that it accepts a comparator to compare the elements and pick the first one that is unique.
We can implement our own unionWith
function as follows:
const unionWith = (comparator, ...arrs) => {
let unionArr = [];
for (const arr of arrs) {
const uniques = arr.filter(a => !unionArr.find(u => comparator(a, u)));
unionArr = [...unionArr, ...uniques];
}
return unionArr;
}
In the code above, we looped through arrs
with a for...of
loop. Inside the loop, we called filter
on arr
to return an array with the ones that aren’t in the unionArr
array and assign the array to the uniques
constant.
Then we spread the values of the existing unionArr
array and the uniques
array and then assign that new array to unionArr
.
Finally, we return unionArr
. Then when we call it as follows:
const result = unionWith((a, b) => Object.is(a, b), [30, 40, 50], [30, 60]);
We get that result
is [30, 40, 50, 60]
since we compared the values with Object.is
to determine if they’re unique or not.
Conclusion
The union
, unionBy
, and unionWith
methods can be implemented with the spread operator and using array’s filter
method.
takeWhile
can be implemented with the for...of
loop and checking for the given predicate in each iteration.