DEV Community

loading...
Cover image for The only thing you need is... reduce

The only thing you need is... reduce

alfredosalzillo profile image Alfredo Salzillo 🐺 ・3 min read

In this article, we will show that the only collection method you need is the Array.prototype.reduce.

Note that this is only to demonstrate all the other methods are only a special case of the reduce.

Only Array methods that don't change the original array will be demostrated.

What is the Array.prototype.reduce

The reduce method is a function that transforms a collection (array) of elements into a single value.

A single value can also be another collection.

We can divide the application of the reduce into 3 equivalent classes.

  1. Type 1 reduce that returns a single Object/number/string, that reduce the collection to another type
  2. Type 2 reduce that returns another collection with the same number of elements
  3. Type 3 reduce that returns another collection with a different number of elements
// Type 1: the sum of the elements of an array
const sum = [1, 2, 3].reduce((acc, value) => acc + value, 0)

// Type 2: convert an array of number to an array of strings
const strings = [1, 2, 3].reduce((acc, value) => [...acc, String(1)], [])

// Type 3: remove even elements
const randoms = [1, 2, 4].reduce((acc, value) => {
  if (value%2 === 0) return acc
  return [...acc, value] 
}, [])
Enter fullscreen mode Exit fullscreen mode

Implemtations

Array.prototype.map

The map method creates a new array with the results of calling a function for every array element.
It is useful to transform all the elements of an array.

Example

// calculate the spare root of all the elements of the array
const result = [4, 9, 16].map((value) => Math.sqrt(value)) // => [2, 3, 4]
Enter fullscreen mode Exit fullscreen mode

It's a Type 2 reduce that return always the same number of elements.

Implementation using reduce:

const map = (array, callbackfn) => array
   .reduce((acc, value, i, thisArg) => [...acc, callbackfn(value, i, thisArg)], [])
Enter fullscreen mode Exit fullscreen mode

Array.prototype.filter

The filter method creates an array filled with all array elements that pass a test (provided as a function).

Example

// return all the even elements
const result = [1, 2, 3].filter((value) => value % 2 === 0) // => [2]
Enter fullscreen mode Exit fullscreen mode

It's a Type 3 reduce that can return an array with a different number of elements.

Implementation using reduce:

const map = (array, predicate) => array
   .reduce((acc, value, i, thisArg) => {
  if (predicate(value, i, thisArg)) return [...acc, value];
  return acc;
}, [])
Enter fullscreen mode Exit fullscreen mode

Array.prototype.some

The some method checks if any of the elements in an array pass a test (provided as a function).

Example

// check if the array contains an even number
const containsAnEven = [1, 2, 3].some((value) => value % 2 === 0) // => true
Enter fullscreen mode Exit fullscreen mode

It's a Type 1 reduce that returns a single value, in this case, a boolean.

Implementation using reduce:

const some = (array, predicate) => array
   .reduce((acc, value, i, thisArg) => (acc || predicate(value, i, thisArg)), false)
Enter fullscreen mode Exit fullscreen mode

Array.prototype.every

The every method checks if all the elements in an array pass a test (provided as a function).

Example

// check if all the elementens of the array are even number
const allEven = [1, 2, 3].some((value) => value % 2 === 0) // => false
Enter fullscreen mode Exit fullscreen mode

It's a Type 1 reduce that returns a single value, in this case, a boolean.

Implementation using reduce:

const every = (array, predicate) => array
   .reduce((acc, value, i, thisArg) => (acc && predicate(value, i, thisArg)), true)
Enter fullscreen mode Exit fullscreen mode

Array.prototype.join

The join method returns an array as a string concatenating the elements using a separator.

Example

// join all strings using a space 
const helloDevs = ['Hello', 'Devs'].join(' ') // => "Hello Devs"
Enter fullscreen mode Exit fullscreen mode

It's a Type 1 reduce that returns a single value, in this case, a string.

Implementation using reduce:

const join = (array, separator) => array
   .reduce((acc, value, i, thisArg) => (acc + separator + value), '')
Enter fullscreen mode Exit fullscreen mode

Array.prototype.flat

The flat method creates a new array with the elements of the subarrays concatenated into it.

Example

const results = [1, [2, 3]].flat() // => [1, 2, 3]
Enter fullscreen mode Exit fullscreen mode

It's a Type 3 reduce that can return an array with more elements than the original.

Implementation using reduce:

const flat = (array, level = 1) => array
   .reduce((acc, value, i, thisArg) => {
    if (!level) return [...acc, value]
    if (Array.isArray(value)) return [...acc, ...flat(value, level - 1)]
    return [...acc, value]
   }, '')
Enter fullscreen mode Exit fullscreen mode

🙏 Please give me some feedback in the comments 🙏

Discussion (8)

Collapse
mdbottino profile image
mdbottino

Actually "some" returns true if it finds an element that passes the test. It doesn't iterate the whole array as reduce would do.
The same is true for "every", it returns false when it finds an element that doesn't pass the test. Again, it doesn't iterate the whole array in that case.

Collapse
alfredosalzillo profile image
Collapse
vonheikemen profile image
Heiker

And with this knowledge you can go one step further and implement those methods as transducers. I've never used them myself, but they are fun to learn.

Collapse
diasbruno profile image
Bruno Dias • Edited

Last week, on a stack meeting, I explained the same derivations using reduce. :)

It's also nice to point out that you can also implement reduce on custom containers.

class Identity { // Just holds a single value 
  constructor(x) { this.x = x; }
  reduce(f, initial) { return f(initial, this.x); }
}

const base = new Identity(1);
base.reduce((acc, x) => acc + x, 10); // 11
Enter fullscreen mode Exit fullscreen mode
Collapse
aminnairi profile image
Amin • Edited

It might be me but I don't think your flat implementation is working as intended. Nice topic though.

What about this implementation instead?. I tried to be as close as possible to the ECMA standard.

Collapse
chayimfriedman2 profile image
Chayim Friedman

The only thing you need is while loop.

If you want to program high-level, you do need those constructs.

However, nice article, as reduce() is less known than its friends :)

Collapse
madza profile image
Madza

It's powerful indeed, tho I always need to look up the sequence of parameters: accumulator, currentValue, currentIndex, array 😀😀

Collapse
alfredosalzillo profile image
Alfredo Salzillo 🐺 Author

Me too 🤣🤣🤣

Forem Open with the Forem app