Forever Functional: The mighty reduce, part 2
Tags: functional, javascript, react, tutorial
Published: 2021-11-17 08:34:19

_by author [Federico Kereki](https://blog.openreplay.com/authors/federico-kereki)_

In our [previous article](https://blog.openreplay.com/forever-functional-the-mighty-reduce) we discussed how  `reduce()` is powerful enough to provide alternatives to other  methods, such as `map()`, `filter()`, and `reduceRight()`. We didn't cover, however, all the available higher-order functions that JavaScript provides. In this article we'll show how to emulate more methods:
* [`every()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) and [`some()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) methods that test if all or any of the elements of an array satisfies a condition;
* [`find()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) and [`findIndex()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) that let you search an array for an element satisfying some condition, and
* [`flat()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat) and [`flatMap()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap) that create a new array by "flattening" (we'll see what this means) its elements, with an optional mapping function thrown in as well.

As in the other article, we'll see that all these methods can be emulated by properly using `reduce()`. And, let's also hurry up and answer a question: should we do such emulation? The answer, again, will be that this is more an exercise in "lateral thinking" about finding new ways of doing things, and about learning more about JavaScript and programming in general. We may not end up using these alternative implementations, but the techniques that we'll use may help in other places.

## Testing for conditions: every() and some()

The two `.every()` and `.some()` methods greatly simplify testing arrays for conditions.

* `every()` is true, if and only if every element of an array satisfies a given predicate; and
* `some()` is true if there is at least one element in an array, which satisfies the given predicate.

Oh, an aside just for Boolean logic buffs: we may use the [duality principle](https://en.wikipedia.org/wiki/De_Morgan%27s_laws), and say that

* `some()` is false, if and only if no element of an array satisfies a given predicate

How can we implement `.every()` and `.some()` based on `.reduce()`? The following ways are a possibility.

```javascript
const every = (arr, fn) => 
  arr.reduce((x,y) => x && fn(y), true);

const some = (arr, fn) => 
  arr.reduce((x,y) => x || fn(y), false);
```

The first implementation ANDs together all the elements in the array, starting with a `true`; the second ORs all elements, and starts with `false`. Because of how JavaScript short-circuits the evaluation of boolean expressions, the `fn()` predicate won't be evaluated again, once the value of `.every()` or `.some()` has been calculated. (For instance, if a value satisfies the predicate, the accumulator in `.some()` will become true, and future evaluations of `x || fn(y)` won't do the second part.) Let's test this, with the help of our `addLogging()` higher order function from our [previous article on higher order functions](https://blog.openreplay.com/forever-functional-higher-order-functions-functions-to-rule-functions).

```javascript
const arr = [22, 9, 60, 56, 12, 4];

const isOdd = (x) => x % 2 === 1;

every(arr, addLogging(isOdd));
// Enter isOdd 22
// Exit  isOdd false

some(arr, addLogging(isOdd));
// Enter isOdd 22
// Exit  isOdd false
// Enter isOdd 9
// Exit  isOdd true
```

The `isOdd()` function tests if its parameter is odd. If we try to see if all the elements in the `arr` array are odd, the first test already fails, and we see that `isOdd()` wasn't called again. If testing whether some elements of the array are odd, after testing 22 and 9 (when the test succeeded) no more calls to the predicate are done. If you wish to, however, think about how to also skip processing the rest of the array. Even if the predicate is no longer called, `.reduce()` will still go through the whole array; a nice exercise!

## Searching an array: find() and findIndex()

Let's now turn to studying `find()` and `findIndex()`. The first one searches an array for the first element that satisfies a given predicate and returns it, or `undefined` otherwise. The second one is similar but returns the index of the element, or -1 if none was found. 

The implementation for the former is similar to that of `every()`. We'll go through the array searching for a value that satisfies the condition, starting with an `undefined` accumulator. When we find an appropriate element, we change the accumulator to the element. For the latter we'll do a similar thing, but we'll keep track of the position of the array, starting with -1.

```javascript=
const find = (arr, fn) => 
  arr.reduce((x,y) => (x===undefined && fn(y) ? y : x), undefined);

const findIndex = (arr, fn) => 
  arr.reduce((x,y,i) => (x===-1 && fn(y) ? i : x), -1);
```

You must remember that `.reduce()` calls your reducing function providing the value of the accumulator, the current element of the array, and finally its index; the latter is the one that we'll keep in `findIndex()`.

## Open Source Session Replay
Debugging a web application in production may be challenging and time-consuming. [OpenReplay](https://github.com/openreplay/openreplay) is an Open-source alternative to FullStory, LogRocket and Hotjar. It allows you to monitor and replay everything your users do and shows how your app behaves for every issue.
It’s like having your browser’s inspector open while looking over your user’s shoulder.
OpenReplay is the only open-source alternative currently available.

![OpenReplay](https://raw.githubusercontent.com/openreplay/openreplay/main/static/replayer.png)

Happy debugging, for modern frontend teams - [Start monitoring your web app for free](https://github.com/openreplay/openreplay).

## Flattening an array: flat() and flatMap()

In [ES2019](https://262.ecma-international.org/10.0/) the new [`flat()`](https://262.ecma-international.org/10.0/#sec-array.prototype.flat) and [`flatMap()`](https://262.ecma-international.org/10.0/#sec-array.prototype.flatmap) methods were added to the language.

The flat operation creates a new array, recursively concatenating all its elements (that may be arrays) up to a specified depth; by default, just 1. For example, imagine you query an API and it returns an array with the orders of a customer, and for each order you have an array of products: something like `arr=[[22, 9, 60], [56], [12, 4]]`. (His first order had three products; the next, one; and the last, two.) We can flatten this into a single array by using `flat()`: `arr.flat()` would be `[22, 9, 60, 56, 12, 4]`.

Flattening the array just one level (as we did in the previous paragraph) is simple. We could do it by spreading, but since we're focusing on the `reduce()` method, let's go that way.

```javascript
const flatOne = arr => 
  arr.reduce((f, v) => f.concat(v), []);
```

We start with an empty array, and we concatenate each element of the array to it. If an element happens to be an array itself, we'll get it "flattened". 

Let's now see how we can totally flatten an array, meaning that if some elements are arrays, whose elements are also arrays, and so on, all will get flattened. Recursion suits the problem naturally; each time we process an element of the array, if it's an array, we flatten it.

```javascript
const flatAll = arr =>
  arr.reduce((f, v) => f.concat(Array.isArray(v) ? flatAll(v) : v), []);
```

Given these two functions, we can now flatten an array at any desired number of levels. We'll use recursion again, and we get a nice implementation.

```javascript
const flat = (arr, n = 1) =>
  n === Infinity                       
    ? flatAll(arr)                     // [1]
    : n === 1
      ? flatOne(arr)                   // [2]
      : flat(flatOne(arr), n - 1);     // [3]
```

According to the `flatMap()` specification, if the level is Infinity, the whole array must be totally flattened, so that's what we do [1]. If we want to flatten it just one level, we use our previous function [2]. And, finally, if we want to flatten the array several levels, we flatten it one level, and we recursively flatten it more levels [3].

What about `flatMap()`? OK, we'll cheat here: that operation is just a `map()` followed by a `flat()` -- and as we've already seen how these two operations can be emulated with the help of flat(), we don't have to do anything special here!


## Summary

We have now completed studying how `reduce()` may be certainly considered the most flexible and potent functional method for  JavaScript programmers. Even if we don't use the implementations seen here, we've studied several techniques and algorithms that may form the base for our own coding. We've always been trying to work functionally, and we now know what's the mightiest tool for that: `reduce()`!