Useful “reduce” use cases
Tags: functional, higherorderfunc, promises, javascript
Published: 2018-09-18 20:12:47

---
title: Useful “reduce” use cases
published: true
tags: fp,higher-order-func,promises,javascript
canonical_url: https://medium.com/@jperasmus11/useful-reduce-use-cases-91a86ee10bcd
---

![](https://cdn-images-1.medium.com/max/1024/1*ji3NuzK3DyQUmg-NUBUtOQ.jpeg)

I recently saw a tweet from a developer stating that he understands the array reduce function, but can not think of many useful use cases for it. In this post, I’ll aim to give a couple of real-world use cases for reduce.

The post will assume you are comfortable with JavaScript Promises; if not, I have a very [simplified primer](https://medium.com/@jperasmus11/roll-your-own-async-compose-pipe-functions-658cafe4c46f) on them in a previous post that you can check out.

### Promise chains

`Promise.all()` is very useful to run numerous promises in parallel, but what if the **order** in which your promises should resolve is important? In that case, you need to run them sequentially. The following function will do exactly that.

```javascript
const promiseQueue = (promiseFn, list) =>
  list.reduce(
    (queue, item) => queue.then(async result => {
      const itemResult = await promiseFn(item);
      return result.concat([itemResult]);
    }),
    Promise.resolve([])
  );
```

### Sum numbers

The most taught and classic example of using reduce is to get the total of an array of numbers, so this list won’t be complete without it. It doesn’t need to be an array of numbers though - you can use more complex data structures.

```javascript
const cities = [
  {
    city: "Chongqing",
    population: 30165500
  },
  {
    city: "Shanghai",
    population: 24183300
  },
  {
    city: "Beijing",
    population: 21707000
  },
  {
    city: "Lagos",
    population: 16060303
  },
  // ...etc
]

const totalPopulation = cities.reduce(
  (sum, city) => sum + city.population,
  0
);
```

### Filter and Map

When you have a data set that needs to be filtered by some criteria and you want to manipulate each remaining item as well, an okay, but slightly naive option would be to first run filter on it and then map over it again essentially doing a lot more looping-over-items than required. A better option would be to use reduce.

Say for instance you have the results of all the students that wrote a particular paper, but you are only interested in the full names of all the students that had a mark of more than 80 out of a hundred.

```javascript
const studentsData = [
  {
    firstName: "Albert",
    lastName: "Einstein",
    score: 53
  },
  {
    firstName: "Charles",
    lastName: "Dickens"
    score: 84
  },
  {
    firstName: "Marilyn",
    lastName: "vos Savant",
    score: 99
  },
  // etc.
];

const smartestStudents = studentsData.reduce(
  (result, student) => {
    // do your filtering
    if (student.score <= 80) {
      return result;
    }

    // do your mapping
    result.push(`${student.firstName} ${student.lastName}`);
    return result;
  },
  []
);
```

### Array to Object conversion

Sometimes you need an object as output from an array and not another array. All other array higher-order functions will _always_ produce an array as output.

Say for instance you have an array of form fields with their validation constraints and you want an object of constraints where the name of the field is the top level keys in the object.

```javascript
const fields = [
  {
    type: 'text',
    title: 'Title',
    name: 'title',
    constraints: {
      required: {
        message: '^Title is required',
        allowEmpty: false
      }
    },
  },
  {
    type: 'text',
    title: 'Slug',
    name: 'slug',
    constraints: {
      required: {
        message: '^Slug is required',
        allowEmpty: false
      },
      format: {
        pattern: '[a-z0-9\_-]+',
        flags: 'i',
        message: '^Can only be a valid slug'
      }
    },
  },
  // etc.
];

const validationRules = fields.reduce(
  (rules, field) => Object.assign(rules, { [field.name]: field.constraints }),
  {}
);
```

This would produce something like this:

```javascript
{
  title: {
    required: {
      message: '^Title is required',
      allowEmpty: false
    }
  },
  slug: {
    required: {
      message: '^Slug is required',
      allowEmpty: false
    },
    format: {
      pattern: '[a-z0-9\_-]+',
      flags: 'i',
      message: '^Can only be a valid slug'
    }
  },
  // etc.
}
```

_Note: if you care about not mutating data, you might consider using `Object.assign({}, rules, { [field.name]: field.constraints })` or using the object spread syntax, `{ ...rules, [field.name]: field.constraints }`. I would advise against this. Personally, I’m a firm believer in the value of immutable data, but with pragmatism. In this case, a new object will be created for each iteration which could end up using quite a lot of unnecessary memory in your app._

### Piping or Composing functions

Sometimes you have a sequence of functions that you want to be invoked for a specific value. The useful functional programming methods, `compose` and `pipe` are perfect for this, but unfortunately, they are not natively part of the JavaScript language (yet!). Not to worry, we can easily write our own:

```javascript
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x)
```

`pipe` is a function that takes a list of functions, calling each function in sequence with the output of the previous function used as the input for the next.

`compose` is very similar; it just invokes the functions in reverse order, from last to first, so it can be implemented like this:

```javascript
const compose = (...fns) => x => fns.reverse().reduce((v, f) => f(v), x)
```

An example could be calculating the checkout total for an online store:

```javascript
const calculateTotal = pipe(
  applyAnySales,
  minusStoreCredit,
  applyCouponCode,
  addTaxes
)

const cardValue = 250;

const total = calculateTotal(cardValue)
```

_If you have any other practical examples of using `reduce` please leave a comment so that I can learn from you._