loading...

Recreating Lodash: _.pull()

amruthpillai profile image Amruth Pillai ・2 min read

I want to start a series where I'll look at various lodash functions and recreate them to the best of my knowledge using plain ol' Javascript.

I did look around for this on DEV, but couldn't find any articles related to this, so saw an opportunity to make one (or maybe I'm just really bad at searching).

I'm starting out with the _.pull() function cause that's one I know how to recreate easily, but feel free to suggest functions in the comments below and I'll consider them for the next edition of the series.

What does it do?

The _.pull() method simply takes an array and a variable number of values after it and modifies the array with the values removed.

let array = ['a', 'b', 'c', 'a', 'b', 'c'];
_.pull(array, 'a', 'c');
console.log(array);
// => ['b', 'b']

How can we make it better?

Now, if there's one thing I do not like, it's functions mutating my original array. I'd much rather have it return a new array thus not modifying the original data.

Another change I'll be making is instead of working on variable arguments, to make this tutorial simple, I'll just pass another array with all the values, so the finished function would look like this:

array = ['a', 'b', 'c', 'a', 'b', 'c'];
result = pull(array, ['a', 'c']);
console.log(result);
// => ['b', 'b']

This is similar to another function in lodash, _.difference(), so we're essentially rebuilding that.

How do we build it?

Right off the bat, we'll be using the Array.prototype.filter() method for this.

Let's write our function definition first.

let pull = (array, values) => {
  // insert magic here
};

Let's call the filter method on the array.

let pull = (array, values) => {
  return array.filter(item => {
    // insert more magic here
  })
};

Now, we're going to check if the item inside the values array exists inside the array. We can do this by using the Array.prototype.indexOf() function.

If the value exists, we would get a non-zero value, so we can return false to remove it from the array, otherwise we can return true to keep it in the array.

let pull = (arr, values) => {
  return arr.filter((item) => {
    return values.indexOf(item) < 0;
  });
};

This is going to churn out our expected output.

Does this really work?

Here's a CodePen to play around with and see the code in action.

Conclusion

Of course, in reality, lodash does a lot more in terms of type checking and it's well built out, but it would pay to know how it works under the hood :)

Do let me know if you find this interesting with a reaction, and if you want to see other functions, mention them in the comments!

Thank you so much for reading! :)

Posted on by:

amruthpillai profile

Amruth Pillai

@amruthpillai

Designer and Developer. The very last of my kind. I belong both on Dribbble and GitHub.

Discussion

markdown guide
 

Hey I like the idea of this article, but I do have a couple of comments:

  • The execution time of your function is heavy if values is large, basically making the execution time O(array.length * values.length). An O(array.length) implementation might look like:
function pull(array, values) {
    const inclusion = new Set(values)
    return array.filter(value=>!inclusion.has(value))
}
  • I find it odd to declare a top level function as a "fat-arrow". It's building something to capture global this and that's wasteful. It requires that you declare functions in sequence, which can become a pain and it's just not clear to me that a const is a function - plus who knows how this gets highlighted - but code pen didn't work out it was a function.

  • Making new arrays all the time has a significant impact on memory and execution time through garbage collection. I get immutability is an important style for reducing complexity, but sometimes it worries me to hell when a developer is taking a temporary array from the previous step and making yet another one.