Map, Filter and Reduce

Understand How to Use Map, Filter, and Reduce in Programming

Let’s start exploring map, filter and reduce what are they exactly ? how we can write our own map, filter and reduce from scratch (yes, I mean polyfills)

Many of you will say they are the higher order functions used for processing and manipulating the arrays. yeah, you are right

Now we will pick each one from Map, Filter and Reduce and learn in depth.

map(): Method used for creating a new array from existing one by applying a function to every element of an array.

so this means map returns a new array not modify the original one right ?

yeah it return the new array by applying the function to all the elements of an original array.

Syntax: array.map((element, index, array) => {})

It takes a callback function with arguments element, index, array

Now let’s implement our own map() function which takes the callback function as an argument and applies all the element of original array.

Array.prototype.customMap = function(callback){
  // checking if provided callback is a function or not
  if (typeof callback !== 'function') {
    throw new TypeError(callback + ' is not a function');
  }

  let temp = [] 
  for(let index=0; index < this.length; index++){
     temp.push ( callback(this[index], index, this) )
  }
 return temp
}

So we have done the custom implementation of built-in Array.prototype.map method in JavaScript.

Now let’s understand it in more detail

  1. Definition:

    • Array.prototype.customMap adds a custom map method to the Array prototype, allowing transformation of array elements based on a provided callback function.
  2. Parameter:

    • callback: A function that is called for each element in the array. It receives three arguments:

      • The current element being processed.

      • The index of the current element.

      • The array itself.

  3. Type Checking:

    • The method checks if the provided callback is a function. If not, it throws a TypeError, ensuring that the method is used correctly.
  4. Temporary Array:

    • An empty array named temp is initialized to store the results of the transformation.
  5. Iteration:

    • A for loop iterates over each element in the array (this refers to the array the method is called on).

    • For each element, the callback function is called.

  6. Transformation:

    • The result of the callback function for each element is pushed into the temp array. This effectively transforms each element according to the logic defined in the callback.
  7. Return Value:

    • After the loop completes, the method returns the temp array, which contains the transformed elements from the original array.

Now the question you might be having what is “this“ which is used in custom implementation

This time wherever we use this keyword understand it like this refers to the array on which the customMap method is called, allowing the function to access and process its elements dynamically.

(We will understand this keyword in detail later on)

Now let’s explore filter()

filter(): Method applies a conditional statement to each element of an array and returns a new array containing only the elements that satisfy the condition.

Syntax: array.filter((element, index, array) => {})

It also takes a callback function with arguments element, index, array

Now let’s implement our custom filter function

Array.prototype.customFilter = function(callback){
  // checking if provided callback is a function or not
  if (typeof callback !== 'function') {
    throw new TypeError(callback + ' is not a function');
  }

  let temp = []

  for(let index = 0; index<this.length; index++) {
      if (callback(this[index], index, this)) {
          temp.push(this[index])                 
      }
  }
  return temp
}
  1. Definition:

    • Array.prototype.customFilter adds a custom filter method to the Array prototype, allowing filtering of array elements based on a provided callback function.
  2. Parameter:

    • callback: A function that is called for each element in the array. It receives three arguments:

      • The current element being processed.

      • The index of the current element.

      • The array itself.

  3. Type Checking:

    • The method checks if the provided callback is a function. If not, it throws a TypeError, ensuring that the method is used correctly.
  4. Temporary Array:

    • An empty array named temp is initialized to store elements that meet the filtering criteria.
  5. Iteration:

    • A for loop iterates over each element in the array (this refers to the array the method is called on).

    • For each element, the callback function is called.

  6. Condition Check:

    • If the callback returns true for the current element, that element is pushed into the temp array.
  7. Return Value:

    • After the loop completes, the method returns the temp array, which contains all the elements that satisfied the condition defined in the callback.

Now let’s look into reduce()

reduce(): Method reduces an array to a single value by executing a callback on each elements of an array and accumulating the result into a final output.

Syntax: array.reduce((accumulator, currentValue, index, array) => {}, initialValue)

Let’s do the custom implementation of reduce() method

Array.prototype.customReduce = function(callback, initialValue){
 // checking if provided callback is a function or not
 if (typeof callback !== 'function') {
    throw new TypeError(callback + ' is not a function');
  }

 if (this.length === 0 && initialValue === undefined) {
    throw new TypeError('Reduce of empty array with no initial value');
  }

 let accumulator = initialValue 

 for(let index=0; index<this.length; index++){
  accumulator=callback(accumulator, this[index], index, this) || this[0] 
 }

 return accumulator
}
  1. Method Definition
    The customReduce method is defined on the Array prototype, allowing all array instances to use it. It takes two parameters:
  • callback: A function that will be called for each element in the array.

  • initialValue: An optional value to start the accumulation.

  1. Callback Type Check
    The method checks if the provided callback is a function. If it's not, a TypeError is thrown with a message indicating the type mismatch. This prevents runtime errors later in the code.

  2. Empty Array Check
    A condition checks if the array is empty and if no initial value is provided. If both conditions are met, it throws a TypeError, preventing the function from operating on an empty array without a starting point.

  3. Initialize the Accumulator
    The accumulator variable is initialized with the initialValue. If initialValue is not provided, it will default to undefined (which will be updated during the first iteration of the loop if necessary).

  4. Iterate Through the Array
    A loop is initiated to iterate over each element in the array.

  5. Invoke the Callback
    Inside the loop, the callback function is called with four arguments:

  • The current accumulated value (accumulator).

  • The current element being processed.

  • The index of the current element.

  • The original array.

The result of the callback function is assigned back to accumulator. If the callback returns a falsy value, this[0] (the first element of the array) is used as the new value for accumulator.

Return the Accumulated Value
After processing all elements, the method returns the final accumulated value stored in accumulator.

Now you might be having the question that why we haven’t checked the array on which map and filter is applied is empty or not because in reduce we have checked whether the array on which reduce is applied is empty or not.

Now recall the behaviour of map() and filter() method

Both map and filter return a new empty array when called on an empty array, as there is no need for accumulation or transformatio. This behavior ensures that the methods are consistent and do not throw errors or produce unexpected results when used with empty arrays.