Build Your Own Filter
To better understand it
Filtering is a common programming pattern in which we iterate over a set of elements and only return a new set of elements that pass the condition provided by a filter function. Unlike mapping, we cannot reverse the process of applying the filter function to get to the original dataset; however, this is possible to achieve in mapping via applying the reverse of the mapping function on the transformed set to get to the original one.
Applying filtering in the context of functional programming will help us achieve readability in a much better sense. All we have to do is provide the original array as well as the filtering function. With this declarative approach, the steps of filtering items from a set of data (array, in the case of this article) is hidden, and we have a focus on the end result we want to achieve.
For example in the picture above, we do provide the initial array of [🍕, 🍔, 🥗, 🍏] and the filtering function
isHealthy. The filter iterates over each of these tasty foods and, based on the filtering function it has, decides which is healthy and which is not. Only the healthy ones will be preserved in the new array and, in the end, returned[🥗, 🍏].
Similar to mapping, we have a few options of filtering elements in an array, with both declarative and imperative approaches.
As you can see, we need to keep track of item indexes, define an initial array, and nest conditional statements inside the
for loop. Even though this way of filtering can be performed, it is not very readable.
Another option we have is to use
forEach, which, like a
for loop, iterates over an array of elements. But the good thing about using it is we don’t have to worry about index tracking. Let’s see it with an example:
This seems like an improvement to the previous alternative in terms of readability, but mutating the
result array outside the context of our iterator is not ideal. It would have been better if we had a filtering method that always returns a new array.
Array.prototype, it iterates on a provided array and invokes a callback on it. This callback, which acts as our filtering function, takes three parameters:
element— the current item in the array being iterated over
index— the index or location of the current element in the array that is being iterated over
array— the original array that the filter method was applied on
Let’s use this filter method as an example. Note that the filter can be applied on any sort of array. In this example, we are going to filter an array of objects based on object property.
With just one line of code, we were able to filter an array of items. That is pretty awesome. Also, as you can see in line 12, chaining mapping and filtering methods can be really useful for working with different types of datasets.
Build a Filtering Function
Own filter function (for loop version)
Abstracting the filtering process with
for loop is very straightforward. We provide the filtering function and original array and let the
FilterLoop handle the filtering process for us.
Own filter function (recursive version)
Now we are going to create a recursive version of the filtering function. Make sure to check to build a recursive version of a mapping function first.
for loop version, we need to pass both an array as well as a filtering function. However, as you can see in line 2, we are destructuring the array parameter and breaking it apart into two new variables called
This approach allows us to decide at each step if we need to return the
head element if it passes the
validFn validation (shown on line 9). If not, we simply ignore the
head the element for that iteration and continue recursively calling the
FilterRecursive function (shown on line 13).
After each iteration, the length of the original array shrinks down until we reach an empty array in the end. It is at that point that
head will be set as
undefined, since we will be trying to destructure an empty array. Then we start returning array elements that passed the validator.
Own filter function (generator version)
This is a very rudimentary example of a filtering function built with generator functions. As you can see in the logs below the code, the generator function returns an
iterator object each time it’s called. With passing our validator function, we are only returning values in the iterator object that passes its validation.