DEV Community

Alex Wiles
Alex Wiles

Posted on • Originally published at alex.uncomma.com

Let's implement the reduce method by refactoring a for-loop

The goal of this post is to show you how the reduce method works and can be implemented by slowly refactoring a simple for loop. Each step will modify one part of the code and at the end we will have an implementation of the reduce method.

originally published on uncomma.com

From a for-loop to reduce

Let's start with a simple script to sum an array of numbers. We define an array, a sum, then loop over each element, adding to the sum. At the end of the script, we print the sum to view the result.

const arr = [1, 2, 3, 4, 5];
var sum = 0;

for (let n of arr) {
  sum += n;
}

console.log(sum);
// 15

We can make this more general and create a sum function that takes an array as an argument and returns the sum of the elements.

This function looks a lot like the script above. It sets the initial state to zero and loops over the array, adding each element to the state. After the loop, the state is returned. We can use this function on any array of numbers now.

const sum = (arr) => {
  var state = 0;
  for (let n of arr) {
    state = state + n;
  }
  return state;
};

sum([1, 2, 3, 4, 5]);
// 15

Now we will start generalizing even more, working our way towards reduce. Rather than hard coding how the state is updated, lets move it into a function. In this next script, "state + n" is replaced with a function call.

var addToSum = (s, val) => s + val;

const sum = (arr) => {
  var state = 0;
  for (let n of arr) {
    state = addToSum(state, n);
  }
  return state;
};

sum([1, 2, 3, 4, 5]);
// 15

And we keep generalizing. Let's replace addToSum with an argument function. Now our sum function takes a second argument: adderFn. Now, when we call sum, we pass in a function that adds the next number (n) to the state (s).

const sum = (arr, adderFn) => {
  var state = 0;
  for (let n of arr) {
    state = adderFn(state, n);
  }
  return state;
};

sum([1, 2, 3, 4, 5], (s, n) => s + n);
// 15

We have one more hardcoded value that we can remove from the function: the initial state. Let's just pass state as an argument.

const sum = (arr, adderFn, state) => {
  for (let n of arr) {
    state = adderFn(state, n);
  }
  return state;
};

sum([1, 2, 3, 4, 5], (sum, n) => sum + n, 0);
// 15

Now we have a function that takes an array, a function, and an initial state. It loops over the array, updating the state by passing the current state and current element to the argument function. This is reduce!

Let's update some variables names and remove any reference to our sum function.

const reduce = (arr, reduceFn, state) => {
  for (let el of arr) {
    state = reduceFn(state, el);
  }
  return state;
};

reduce([1, 2, 3, 4, 5], (s, n) => s + n, 0);

We can define this function on the array prototype, so it looks like the native reduce. The main difference is we no longer take an array argument.

Array.prototype.reduce = function(reduceFn, state) {
  for (let el of this) {
    state = reduceFn(state, el);
  }
  return state;
};

[1, 2, 3, 4, 5].reduce((s, n) => s + n, 0);

And that's it. We just refactored a simple for loop into the reduce function.

Check out some reduce examples here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce#Examples

If you like this style of post, sign up for the newsletter here or know on twitter @xwle

Top comments (0)