JavaScript Reduce - A Complete Guide to the Only JS Array Function You Really Need
Tags: javascript
Published: 2024-01-11 14:37:23

---
title: JavaScript Reduce - A Complete Guide to the Only JS Array Function You Really Need
published: true
date: 2024-01-11 06:09:00 UTC
tags: javascript
canonical_url: https://www.stephanmiller.com/javascript-reduce/
---

While the JavaScript `map`, `filter`, and `find` functions will help you do a lot with JavaScript arrays, every now and then, you have to do more than what these methods can handle. JavaScript `reduce` is the Swiss Army knife of array manipulation in JavaScript that can not only do what these other functions can’t but also everything they can.

## What is the JavaScript `reduce` Function?

The textbook definition of JavaScript `reduce` is:

> JavaScript reduce is a higher order JavaScript function used for manipulating data that reduces an array to a single value.

**But what this definition doesn’t tell you is that this “single value” can be anything: number, string, array, or object.** And that definition is what kept me from using it for a long time unless I needed to do something like get the sum of an array of numbers.

The `reduce` method of JavaScript runs a callback function on every element in an array. In this function, you use what is called an “accumulator” that you have complete control over. Just think of it as another variable where you collect everything you need from the original array.

## JavaScript `reduce` Syntax

Here is the syntax of JavaScript reduce:

```
reduce(callbackFunction, initialValue)

```

The `initialValue` is optional, but you will want to set it most of the time, unless, for example, you are just summing an array of numbers or concatenating an array of strings. If you don’t add the `initialValue`, which becomes the `accumulator` mentioned in the last section, the first element of your array (`myArray[0]`) will be used as the initial value and iteration through the array will start on the next element (`myArray[1]`).

Now let’s look at the syntax for the callback function:

```
callbackFunction(accumulator, currentValue, currentIndex, array)

```

Here is what each of these arguments are:

- **accumulator:** When the function is first called this is the `initialValue` you added as the second argument of the reduce method. If there is no `initialValue`, it is the first element of the array being reduced. As the function is run on the array, you can modify this accumulator and the modifed accumulator gets passed back in.
- **currentValue:** This is the current element of the array that the function is acting on. If you used an initialValue, the first call will be on `array[0]`. If not, it will be `array[1]`.
- **currentIndex:** This is the index of the current element of the array that the function is acting on.
- **array:** This is the full value of the array that the reduce function is acting on.

So, basically, when using `reduce`, you have access to just about information you need about the array, though in most instances, you will only have to use the first two parameters of the callback function. And when the `reduce` function has acted on every element in the array, it returns the final state of the `accumulator`.

## How to Use `reduce` in JavaScript

Before we get into specific examples, let’s look at one simple example using reduce without an initial value. This code simply takes an array that contains the alphabet and concatenates it into a string:

```
const alphaArray = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];

const alphaString = alphaArray.reduce((accumulator, currentValue) => {
  return accumulator + currentValue;
});

console.log(alphaString);

```

The reduce function loops over the `alphaArray` and concatenates the next value to the accumulator. The result of this code will be:

```
abcdefghijklmnopqrstuvwxyz

```

In the next example, we are going to use reduce with an initial value. Here we have two arrays: one with the keys of the object we want to create and one with the values.

```
const keys = ['name', 'age', 'city'];

const values = ['John Doe', 25, 'New York'];

const result = keys.reduce((obj, key, index) => {
  obj[key] = values[index];
  return obj;
}, {});

console.log(result);

```

And here is the result:

```
{
  age: 25,
  city: "New York",
  name: "John Doe"
}

```

In this use of reduce, we used different argument names for our callback function to better explain what values are being acted on.

- accumulator = obj (the initial value is an empty object)
- currentValue = key (from the keys array that is being reduced)
- currentIndex = index

And you should be able to see some of the magic that is possible with JavaScript reduce.

Our initial value is an empty object (`{}`) and it gets built up using these two arrays. But we only have to use `reduce` on one and then we can use the index of the current value in that array to get the value of the element with the same index in the other array to create the object.

While this might seem like a toy example, think of parsing CSV into a JSON object with the `keys` array being the first row in the CSV and it just gets more complicated after that, but we will look at that and other specific examples in the next section.

## JavaScript `reduce` Examples

Like I was saying earlier, you can do just about anything you want to do with an array using reduce. Here are some examples.

### Using JavaScript `reduce` to Sum

When I first learned about `reduce`, this was all I thought it could do, so let’s look at this example first:

```
const numbers = [1, 2, 3, 4, 5];

const sum = numbers.reduce((accumulator, currentValue) => {
  return accumulator + currentValue;
}, 0);

console.log(sum); // result: 15

```

To being, we set the `initialValue` of the `accumulator` to `0`, so we can add the numbers in the array to it.

Then, for each `currentValue` in the `numbers` array, we add it to the `accumulator`.

When the iterations are done, the final result is stored in the `sum` variable.

### Using JavaScript `reduce` on an Array of Objects

Using `reduce` on an array of objects is not much different from using it on an array of values. Here is an example where our array contains a shopping list with the `name`. `price` and `quantity` of each item purchase and we want a total:

```
const products = [
  { name: 'Apple', price: 0.5, quantity: 10 },
  { name: 'Banana', price: 0.25, quantity: 5 },
  { name: 'Orange', price: 0.3, quantity: 8 }
];

const totalCost = products.reduce((accumulator, product) => {
  return accumulator + product.price * product.quantity;
}, 0);

console.log(totalCost); // result: 7.9

```

Inside the `reduce` method, we start with an initial value of `0` for the `accumulator`. Then, for each `product` object in the `products` array, we compute the cost by multiplying the `price` and `quantity` properties, and add it to the `accumulator`.

The `reduce` method iterates over each object in the `products` array, continuously accumulating the total cost.

### Using JavaScript `reduce` on an Object

What? Yes, I know `reduce` is for arrays, but `Object.keys()` returns an array of the keys in an object. Here is how we can use this:

```
const person = {
  name: 'John',
  age: 30,
  city: 'New York'
};

const transformedObject = Object.keys(person).reduce((accumulator, key) => {
  accumulator[key.toUpperCase()] = person[key];
  return accumulator;
}, {});

console.log(transformedObject);
/*
Result
------
{
  AGE: 30,
  CITY: "New York",
  NAME: "John"
}
/*

```

In the code above, we have an object and we want to convert the keys to uppercase.

Inside the `reduce` method, we use `Object.keys(person)` to get an array of keys from the `person` object. This allows us to iterate over each key.

For each key, we assign the corresponding value from `person[key]` to a new property in the `accumulator` object with the key converted to uppercase (`key.toUpperCase()`).

The `reduce` method iterates over each key in the `person` object, building up the `accumulator` object with the transformed properties.

### Using JavaScript `reduce` to Flatten an Array of Arrays

Here is how you flatten an array of arrays into a single level array using `reduce`

```
const nestedArray = [[1, 2], [3, 4], [5, 6]];

const flattenedArray = nestedArray.reduce((accumulator, currentArray) => {
  return accumulator.concat(currentArray);
}, []);

console.log(flattenedArray); // result [1, 2, 3, 4, 5, 6]

```

Setting our initial value to an empty array, we simply return the `accumulator` after concatenating the `currentArray` in the iteration. These arrays didn’t have duplicates, but if they did, the next section will show you how to remove them.

### Using JavaScript `reduce` to Remove Duplicates in an Array

It’s easy to remove duplicates in an array with `reduce`. Here’s how:

```
const numbers = [1, 2, 3, 4, 4, 5, 2, 6, 3, 7];

const uniqueNumbers = numbers.reduce((accumulator, currentValue) => {
  if (!accumulator.includes(currentValue)) {
    accumulator.push(currentValue);
  }
  return accumulator;
}, []);

console.log(uniqueNumbers); // result [1, 2, 3, 4, 5, 6, 7]

```

Inside the `reduce` method, we use an empty array (`[]`) as the initial value for the `accumulator`. Then, for each element (`currentValue`) in the `numbers` array, we check if it is already present in the `accumulator` using the `includes` method. If the element is not present, we push it into the `accumulator`.

### Using JavaScript `reduce` to Reverse an Array

You can also reverse an array using `reduce`:

```
const array = [1, 2, 3, 4, 5];

const reversedArray = array.reduce((accumulator, currentValue) => {
  return [currentValue, ...accumulator];
}, []);

console.log(reversedArray); // result: [5, 4, 3, 2, 1]

```

Here, we add the `currentValue` at the beginning of the array and then use the spread operator to put the current contents of of the `accumulator` (the array we are building) at the end.

### Using JavaScript `reduce` for Array Intersection

You can use JavaScript’s `reduce` method to find all elements that are common in a list of arrays. Here’s how:

```
const arrays = [
  [1, 2, 3, 4, 5],
  [4, 5, 6, 7],
  [3, 4, 5, 8]
];

const intersection = arrays.reduce((accumulator, currentArray) => {
  return accumulator.filter((element) => currentArray.includes(element));
});

console.log(intersection); // result [4, 5]

```

Here we use the `accumulator` to collect all the common values. Then we use the JavaScript `filter` method to check if each element in the `accumulator` is present in the `currentArray` using the `includes` method. Only elements that fit this condition are kept in the `accumulator`.

### Using JavaScript `reduce` to Create a Pipeline of Functions

If you want to run a bunch of different functions on a value, you can create those functions separately and then use `reduce` to create a pipeline that runs them in order. Here is an example:

```
const addOne = (a) => a + 1;
const multiplyByTwo = (a) => a * 2;
const divideByThree = (num) => num / 3;

const pipeline = [addOne, multiplyByTwo, divideByThree];

const result = pipeline.reduce(function(total, func) {
  return func(total);
}, 8);

console.log(result); // result: 6

```

Here, we the value we are modifying is set at the initial value, the array contains our functions, and we iterate over them, we run them on the initialValue/accumulator. If we wanted to, we could wrap the method in another function and pass in the value we want as the `initialValue`. We could even take it further and turn this new function into a callback for another `reduce` and apply all three functions to all elements in another array.

### Using JavaScript `reduce` to Convert CSV into a JSON Object

Earlier in the article, I mentioned showing how to convert a CSV document into JSON. The only thing I don’t have in this code is reading the file:

```
const csvData = `Name,Age,City
John,25,New York
Jane,30,San Francisco
Alex,35,Seattle`;

const rows = csvData.split('\n');
const headers = rows[0].split(',');

const jsonData = rows.slice(1).reduce((accumulator, row) => {
  const values = row.split(',');
  const obj = headers.reduce((objAccumulator, header, index) => {
    objAccumulator[header] = values[index];
    return objAccumulator;
  }, {});

  accumulator.push(obj);
  return accumulator;
}, []);

console.log(jsonData); // result is next code block

```

First, we do some data prep and split the `csvData` string into an array of rows using the newline (`\n`) character as the delimiter. We also split the first row (header row) into an array of headers, so that it can be used during the process to set the object keys.

Inside the `reduce` method, we start with an empty array (`[]`) as the initial value for the `accumulator`. Then, for each row (starting from index 1 to exclude the header row), we split the row into an array of values using the comma (`,`) as the delimiter.

Inside the nested `reduce` method, we iterate over the `headers` array. For each header, we assign the corresponding value from the `values` array to the corresponding property in the `obj` object. Notice that this `reduce` methods `initialValue` is an empty object (`{}`).

This is a use case for the `currentIndex` parameter in a `reduce` callback. Since the header array length and each of the rows are the same size, we use the `index` of the current `headers` element to find the corresponding value in the row.

After processing all headers and values, we push the `obj` object into the `accumulator` array.

And the result:

```
[{
  Age: "25",
  City: "New York",
  Name: "John"
}, {
  Age: "30",
  City: "San Francisco",
  Name: "Jane"
}, {
  Age: "35",
  City: "Seattle",
  Name: "Alex"
}]

```

## Replacing JavaScript `map`, `filter`, and `find` with `reduce`

You can also use JavaScript `reduce` to replace these other array methods. Why would you want to do that? Because you might want to do multiple things in one pass over the array instead of running multiple functions in multiple passes over the array and this shows you how to recreate those with `reduce` so you can add more functionality.

### Replacing JavaScript `map` with `reduce`

If you are wondering, “JavaScript reduce vs map, which should I use”. First, `map` can only return an array of the same size. You can manipulate all the values in the array, but the return will be the same length. Here is an example of using JavaScript `map` to double the value of each number in an array:

```
const numbers = [1, 2, 3, 4, 5];

const doubledNumbers = numbers.map((num) => num * 2);

console.log(doubledNumbers); // result: [2, 4, 6, 8, 10]

```

The JavaScript map method creates a new array, multiplying each number in the array by 2.

And here we do the same thing with reduce:

```
const numbers = [1, 2, 3, 4, 5];

const doubledNumbers = numbers.reduce((result, num) => {
  result.push(num * 2);
  return result;
}, []);

console.log(doubledNumbers); // result: [2, 4, 6, 8, 10]

```

Here, the accumulator parameter is named `result` and the current value is `num`. We start with an empty array as our initial value. The `reduce` method iterates over each element in the `numbers` array, doubles it, and adds the result to the `result` array. When it is done, our callback function returns the `result` array.

### Replacing JavaScript `filter` with `reduce`

Unlike JavaScript `map`, JavaScript `filter` can return a shorter array than the original because it filters the array. Here is an example of using JavaScript `filter` to return an array with only even numbers:

```
const numbers = [1, 2, 3, 4, 5];

const evenNumbers = numbers.filter((num) => num % 2 === 0);

console.log(evenNumbers); // result: [2, 4]

```

The `%` is the JavaScript remainder operator. It returns the remainder left over when one number is divided by another and even numbers, when divided by 2, have no remainder.

Here is how to replace JavaScript `filter` with `reduce` in this case:

```
const numbers = [1, 2, 3, 4, 5];

const evenNumbers = numbers.reduce((result, num) => {
  if (num % 2 === 0) {
    result.push(num);
  }
  return result;
}, []);

console.log(evenNumbers); // result: [2, 4]

```

This is similar to the `map` replacement example, except we only want to add even numbers to the resulting array. We use the remainder operator again here and when the number passes our even check, we add it to the array. If not, we just return the array as is.

### Replacing JavaScript `find` with `reduce`

JavaScript `find` returns the first element in an array that passes the testing function. Below we want to find the first number in this array that is greater than 10.

```
const numbers = [5, 50, 8, 145, 3];

const found = numbers.find((num) => num > 10);

console.log(found); // result: 50

```

And here is how we can replace find with reduce:

```
const numbers = [5, 50, 8, 145, 3];

const found = numbers.reduce((result, num) => {
  if (result === undefined && num > 10) {
    result = num;
  }
  return result;
}, undefined);

console.log(found); // result: 50

```

The code above is different from the other examples. This is because `find` returns the first element matching our check. To do that with `reduce`, we set the initial `value` to `undefined`. We also check that it is still `undefined` before setting our result. If we didn’t, it would return the last number in the array that passes our test or 3.

## How to Break Out of JavaScript `reduce`

What you might notice when we replaced JavaScript `find` with JavaScript `reduce` in the last example, there is some wasted processing going on. After all, we found the number in the second element of the array, yet the code stills runs until it hits the end.

Unfortunately, there is no way to break out of the `reduce` method at this point. Well, there is, but not something you would really want to use. Here’s how:

```
const numbers = [5, 50, 8, 145, 3];

try {
  const found = numbers.reduce((result, num) => {
    if (num > 10) {
      throw new Error(`${num} found. Breaking out of reduce.`);
    }
    return result + num;
  }, 0);
} catch (error) {
  console.log(error.message); // result: "50 found. Breaking out of reduce."
}

```

Like I said, not the best way, so with `reduce`, we are stuck with looping through the whole array.

## JavaScript `reduce` with Async/Await

There are a few ways to do this, but my favorite is using `Promise.all`, since will execute all the promises in parallel. In this example, we want to fetch data from multiple APIs and return the results:

```
async function fetchDataInParallel(urls) {
  try {
    const promises = urls.reduce((accumulator, url) => {
      accumulator.push(fetch(url).then(response => response.json()));
      return accumulator;
    }, []);

    const results = await Promise.all(promises);
    return results;
  } catch (error) {
    console.error('Error fetching data:', error);
  }
}

const urls = [
  'https://random.dog/woof.json',
  'https://cataas.com/api/cats?tags=cute&limit=3'
];

fetchDataInParallel(urls)
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error)); // result below

```

First, we create a reusable function that we can pass in our array of `urls` to hit. We add a `try...catch` block around the functions to handle potential error.

`const promises = urls.reduce(...)` creates an array of promises:

- `accumulator.push(fetch(url).then(response => response.json()))`: Pushes a promise for each fetch operation into the accumulator.
- `return accumulator`: Returns the updated accumulator for the next iteration.
- `[]`: Initial accumulator is an empty array to store promises.

Then, `const results = await Promise.all(promises)` waits for all the promises to resolve and collects the results and the results are returned.

And here are the results. I don’t know what you would use this data for, since I picked random public APIs, but the code is currently fully functional.

```
[{
  fileSizeBytes: 107720,
  url: "https://random.dog/e00b0661-9c04-463c-8f88-612613dd0ea0.jpeg"
}, [{
  _id: "3zM2HCQRdiZHB3Oo",
  mimetype: "image/jpeg",
  size: 22511,
  tags: ["calico", "sleepy", "cute", "fat", "luna"]
}, {
  _id: "aonUpTntYMPno4yt",
  mimetype: "image/jpeg",
  size: 38309,
  tags: ["fat", "tricolor", "cute", "calico"]
}, {
  _id: "zeAG7BfSGsweyeSO",
  mimetype: "image/jpeg",
  size: 36719,
  tags: ["cute", "face", "white"]
}]]

```

## So What Is JavaScript `reduceRight`?

This is simply JavaScript `reduce` that runs backwards. Instead of iterating from the beginning of the array, it starts at the end. The syntax is the same as `reduce`. Here is our first example using `reduceRight` instead of reduce:

```
const alphaArray = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];

const alphaString = alphaArray.reduceRight((accumulator, currentValue) => {
  return accumulator + currentValue;
});

console.log(alphaString); // result: zyxwvutsrqponmlkjihgfedcba

```

And instead of concatenating the alphabet in order, it does it in reverse order.

## Conclusion

In this article, I wanted to help people get over the hurdles of learning JavaScript `reduce`, because it is a really useful tool and its definition and syntax description aren’t really enough to demonstrate its power. Hopefully, some of these examples helped you see how useful it can be. So, go forth and reduce some things.