The Most POWERFUL [JavaScript] Function
Tags: javascript, code, tutorial, programming
Published: 2021-07-28 08:35:17



{% user cleancodestudio %}

[![Twitter Follow](https://img.shields.io/twitter/follow/cleancodestudio.svg?style=social)](https://twitter.com/cleancodestudio) 


>
> Did you know I have a newsletter? 📬
>
> If you want to get notified when I publish new blog posts or
> make major project announcements, head over to 
> https://cleancodestudio.paperform.co/
>

---

## The most POWERFUL [JavaScript] Function

---

> _"`Today you learn how to use **THE MOST POWERFUL** JavaScript Function out there.`"_


---

## Array.reduce

---

> _"`Array.reduce` is **THE MOST POWERFUL** `JavaScript Function.` **PERIOD.**"_


- Yah - okay, you got me. _Technically_ this is my opinion.
- That being said, I full-heartedly believe in this opinion.
- Yep, after this post, I'm hoping you share this opinion too!

---

At the end of this article, I openly invite you to challenge this opinion of mine in the comments section. I'm down for a comments war that shares contradicting perspectives :)

With that being said, let's dive in!


---

### Article Structure & Related Resources

---

#### **Article Structure**
- Easy examples
  - Are at the beginning of the article
  - Are not intended to be real world use cases
  - Are meant to teach how to utilize reduce simply
  - Are intended to reduce by replacing functions with reduce 
  - Can skip if you already understand how to implement reduce
- Intermediate examples
  - Are after the easy examples
  - Are intended to show some real world use cases 
  - Are not intended to explain the most powerful parts of reduce
- Advanced examples
  - Found after the intermediate examples
  - Intended to show real world use cases
  - Intended to explain more powerful real-world reduce use cases
- Expert and rarely talked about reduce Tips/Tricks 
  - All of, Array.reduce's accumulator callback parameters
  - How to break out of Array.reduce's loops similar to break
  - How to mutate the original source array reduce has access to

#### **Related Resources: Array.Reduce YouTube Video**
- Video code example walk throughs
- YouTube video and this article have very similar content
- Note: It's simpler to understand some examples via video 

{% youtube WGleM3FeZmU %}


---

## Array.reduce


---


> _What does reduce do? Why is it so powerful?_

Well, here's the technical definition of reduce...

`Array.prototype.reduce()`

---


_The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in a single output value._


> _Not very helpful if you ask me, so LET'S LEARN BY DOING_


---

### 1. Find total of all numbers summed (using reduce) 

---

```js

[3, 2.1, 5, 8].reduce((total, number) => total + number, 0)

// loop 1: 0 + 3
// loop 2: 3 + 2.1
// loop 3: 5.1 + 5
// loop 4: 10.1 + 8
// returns 18.1

```

---

### 2. Find total of all numbers multiplied

---

```js
[3, 2.1, 5, 8].reduce((total, number) => total * number, 1)
```



> _As shown, it's pretty easy to add or multiply all of the numbers in an array. But, c'mon - I said reduce is THE MOST POWERFUL FUNCTION IN ALL OF JS._


> _Obviously, there has to be more to reduce - right?_

Let's say we have `3`, `4`, `10`, and `60`. Let's say we want to get _some_ of the values. 

Or, more specifically, we want to `filter` the values and only return the values if they are less than 10. 

Normally, we can simply use the `filter` function and only return the numbers if they are less than 10.

---

### 3. Array.Filter using reduce

---

```js
[3, 4, 10, 60].filter(number => number < 10)
```


Well, with reduce - we can do the exact same thing.


```js
[3, 4, 10, 60].reduce((list, number) => 
   number < 10
      ? [...list, number]
      : list
, [])
```

> _And lala, we replaced filter with reduce - pretty cool but let's be honest. This STILL DOESN'T justify `reduce` as being **THE MOST POWERFUL FUNCTION IN ALL OF JavaScript**._


---

> _What if I told you, we could continue down this path and replace just about every array function in JavaScript using reduce?_

---


---

### 3. Re-creating `Array.some` using `Array.reduce`

---

```js
[3, 4, 10, 50].some(number => number < 50)

// returns true (We have some numbers in the array are less than 50)
```

> _Using reduce, we simply set the initial value to false. If the condition is already true then we return the condition. If the condition is not already true then we check if the current number meets our condition._

```js
[3, 4, 10, 50].reduce((condition, number) => 
   condition === true  
       ? condition
       : number < 50
, false)
```


> _Notice, this time we start with a bool (false) as our initial value instead of using a number or an array._


---


> _We have now summed, multiplied, filtered, and re-created some (aka conditionally checking something on our array using reduce)._

> _We could go on to also replace the `Array.every` function using `Array.reduce`, but since that is similar to replacing `Array.some` using `Array.reduce` we'll just note that we can easily do that as well._


---

### 4. What about `Array.join` using `Array.reduce`?

---

> _Replacing `Array.join` with `Array.reduce`_

```js
['truck', 'car', 'people'].join('-')

// "truck-car-people"
```

> _Using `Array.reduce` we can code the following_
```js
['truck', 'car', 'people'].reduce((text, word) => `${text}-${word}`, '')

// "-truck-car-people"
```

> _Notice the output has a preceding dash at the front._

> _The callback function accepted as the first argument for the `Array.reduce` function accepts more parameters. We can use the third accepted parameters to track our `index` for our reduce function_


```js
['truck', 'car', 'people'].reduce((text, word, index) => 
    index === 0
       ? word 
       : `${text}-${word}`
, '')

// "truck-car-people"
```

> _With that 3rd parameter set up, this reduce function will now act exactly how the original `Array.join` acts_


---

With that, so far we have used reduce to replace.

- Array.map
- Array.filter
- Array.every, Array.some
- Array.join

---

### 5. Array.concat using Reduce

---

> _What about concat? Where you can concat an array of "1", "2", and "3" with another array?_


```js
[1, 2, 3].concat(['hey', 'world', 'mars'])

// [1, 2, 3, 'hey', 'world', 'mars']
```


> _How would you concat or combine arrays reduce?_


```js
[[1,2,3], ['hey', 'world', 'mars']].reduce(
   (list, array) => [...list, ...array],
[])

// [1, 2, 3, 'hey, 'world', 'mars']
```

> _What's cool about combining arrays using `Array.reduce` is that we can "concat" as many arrays as we want to._

> _Simply, by passing in more arrays we will automatically combine aka concatenate them using reduce._


> _With that, we have replicated `Array.concat` using `Array.reduce`_


---

> _Let's get into a few more examples._


> _First, let's create a few people._
```js
let sarah = { name: 'sarah', email: 'sarah@gmail.com', id: 1 }
let tim = { name: 'tim', email: 'tim@gmail.com', id: 2 }
let len = { name: 'len', email: 'len@gmail.com', id: 3 }
```

---

### 6. Grouping People By Names using `Array.reduce`

---

**Example of what we want when we group people by names**

```js
people.len

// Gets Len
// { name: 'len', email: 'len@gmail.com', id: 3 }


people.sarah

// Gets sarah
// { name: 'sarah', email: 'sarah@gmail.com', id: 1}
```


> _Grouping people by their names using reduce_
- Make the initial value for our reduce function an object
- Build an object where 
  - The key is the person's name ([person.name]) 
  - The value is the person object ([person.name]: person)

**Example (That won't work)**
```js
let people = [sarah, tim, len].reduce((people, person) => {
   [person.name]: person,
   ...people
}, {}) 
```

> _In the example above we'll get an error_

**Uncaught SyntaxError: Unexpected token ':'**


> _Whenever we use a short hand function to return an object we need to wrap it in parentheses_
- Wrap the returned object's brackets in parentheses to fix the error 


```js
let people = [sarah, tim, len].reduce((people, person) => ({
   [person.name]: person,
   ...people
}), {}) 
```

> _And lala, we now have a people object where the people are grouped by their name_


If we go `people.len` we get len
```js
people.len // { name: 'len', email: 'len@gmail.com', id: 3 }
```

If we go `people.sarah` we get sarah

```js
people.sarah // { name: 'sarah', email: 'sarah@gmail.com', id: 1 }
```

If we go `people.tim` we get tim

```js
people.tim // { name: 'tim', email: 'tim@gmail.com', id: 2 }
```

If we want all of our `people`?

```js
// people 
{
   sarah: { name: 'sarah', email: 'sarah@gmail.com', id: 1 },
   tim: { name: 'tim', email: 'tim@gmail.com', id: 2 },
   len: { name: 'len', email: 'len@gmail.com', id: 3 },

}
```

---

### 7. Plucking an array of values by a given key using Reduce 

---

> _More than that, what if we wanted to get **just** the names of the people?_

```js
let names = [sarah, tim, len].reduce((names, person) => [
   ...names,
   person.name
], [])

// ['sarah', 'tim', 'len']
```


> _What if we wanted to get **just** the emails of the people?_

```js
let emails = [sarah, tim, len].reduce((emails, person) => [
   ...emails,
   person.email
], [])

// ['sarah@gmail.com', 'tim@gmail.com', 'len@gmail.com']
```



---

### 8. Flattening multiple levels of nested Arrays using Reduce

---

> _More than that, what if we had an array of nested arrays?_

```js
let list_of_arrays = [
    ['sub_one', 'sub_two', 'sub_three'],
    [
       ['nested_sub_one', 'nested_sub_two'], 
       ['nested_sub_three', 'nested_sub_four']
    ],
    'one',
    'two',
    'three'
]
```

> _Let's take our list of arrays, and lets of course use reduce_

```js
list_of_arrays.reduce((flattened, item) => {
   if (Array.isArray(item) === false) {
      return [...flattened, item]
   }
   if (Array.isArray(item) && Array.isArray(item[0])) {
      return [
         ...flattened,
         ....item.reduced((flatten, nested_list) => [...flatten, ...nested_list, [])
       ]
      ]
   }
   
   return [...flattened, ...item]
}, [])
```

> _And lala, we've flattened our list of multiple level nested arrays._

**Output**
```js
["sub_one", "sub_two", "sub_three", "nested_sub_one", "nested_sub_two", "nested_sub_three", "nested_sub_four", "one", "two", "three"]
```

**Note:**

> _We only handled nested sub arrays up to 3 levels deep, but you could of course spend some more time on the function and use recursion to pretty simply flatten an array infinite nested levels deep using reduce._


---

## More POWERFUL use cases for Reduce

---

> _Alright, so now let's dive into some of the more Powerful, not as oftenly used - use cases for `Array.reduce`._


---

### 9. Apply Formatters on Strings

---


I'm going to start off with an array of strings.

```js
let strings = ['cool-link', 'hello world of javascript', 'goodbye, its been swell']
```

Next let's create an array of `formatters`. Normally, I'd call these filters - but they're not really filters. They're just formatting the string.


These formatters are actually going to be callback functions.

First, we'll create a dashes to spaces formatter (replace dashes with spaces). Will use regex to implement this formatter.

```js
let dashesToSpaces = str => str.replace(/-/g, ' ')
```

Next, we'll create a capitalize string formatter.

```js
let capitalize = str => `${str[0].toUpperCase()}${str.slice(1)}`
```

Then, we'll create a string limiter formatter. 

If the string is greater than a given length, replace the characters after that length limit with three dots.

```js
let limiter = str => str.length > 10 ? `${str.slice(0, 10)}...` : str 
```


Finally, we'll create a `formatters` array with all of our string formatters.


```js
let formatters = [dashesToSpaces, capitalize, limiter]
```


---

Remember we have our array of strings. 

```js
let strings = ['cool-link', 'hello world of javascript', 'goodbye, its been swell']
```

**Our Goal:**

> _Our goal is to apply every single formatter from our formatters array onto every single string from our strings array._



Using reduce, we can simply do this like so!

```js
strings.reduce((list, str) => [
      formatters.reduce((string, format) => format(string), str),
      ...list
   ],
[])
```

> _And just like that, we used reduce to apply an array of formatters on an array of strings. _

**Original Strings Array**
```js
['cool-link', 'hello world of javascript', 'goodbye, its been swell']
```

**Output (After using reduce to apply string formatters)**
```js
["Goodbye, i...", "Hello worl...", "Cool link"]
```


---

### 10. Group students by rooms (using reduce)

---


> _First let's create some students_

```js
let students = [
   { name: 'Sally', room: 'A' },
   { name: 'tim', room: 'A' },
   { name: 'nick', room: 'B' },
   { name: 'rick', room: 'C' },
   { name: 'sarah', room: 'B' },
   { name: 'pam', room: 'C' }
]
```


> _We want to group the students by their room_


So what we're going to do is use `students.reduce`.

```js
students.reduce((class_rooms, student) => ({
}), {})
```

Notice we use the parentheses around the object we're implicitly returning again. When we use a short hand function to return an object we have to use `({})` syntax - if we attempt to directly return an object without the wrapping `()` we'll get an error. 



Next, we want to use the student room as the key:

```js
students.reduce((rooms, student) => ({
   ...rooms,
   [student.room]: rooms[student.room]
        ? [...rooms[student.room], student]
        : [student]
}), {})
```

Now, we have our students grouped by their rooms/classes.


```js
{
   A: [{ name: 'sally', room: 'A' }, { name: 'tim', room: 'A' }],
   B: [{ name: 'nick', room: 'B' }, { name: 'sarah', room: 'B'}],
   C: [{ name: 'rick', room: 'C' }, { name: 'pam', room: 'C' }],
}
```


We have successfully grouped our students by their rooms - so that is how we group by reduce. 


---


So guys, that's about all I've got with reduce. I guess the biggest takeaway is that reduce is a super method - it really is!

You can do just about anything you can do with _any_ other Array method using reduce. 

Instead of going `Array.filter.map.filter.forEach`, you could use a single reduce function to accomplish the same goal. 

If you need to group a whole bunch of object by their keys, use reduce.

If you need to pluck the values related to a given key? Use reduce. 

If you need to apply multiple filters but don't want to raise the time complexity by iterating multiple times over through the same array - use reduce.

If you want to flatten an array of nested arrays where each nested array may have more nested array while each nested array also may not have any nested arrays? Use reduce.

If you need to sum some number, multiply some numbers, subtract sum numbers, or do some arithmetic of any sort - reduce works again.

What if you need to combine some arrays? Use reduce.

What if you need to combine some objects? Use reduce.

What if you want to have a method in your back pocket that you know can do it all and just makes you feel more powerful and efficient as a software engineer? 

Use reduce!

In my opinion, forEach is the most over rated method in the JavaScript eco-system and reduce is the **most** under rated method in the JS eco-system.


----


As a final example of how cool reduce is let's take this final example.

```js
[{ name: 'Clean Code Studio' }, { belief: 'Simplify!' }, { should_follow: 'Si, senor!' }].reduce((last_example, partial) => ({ 
   ...last_example, ...partial }), {})

```

What does this return? It merges all of the objects.

```js
{

   name: 'Clean Code Studio',
   belief: 'Simplify',
   should_follow: 'Si, senor!'
}
```

{% user cleancodestudio %}


Using reduce you can filter, you can apply, you can apply a list of callbacks, you can flatten, merge, combine...

I _highly_ recommend that you become familiar, competent, and over all familiar when it comes to using reduce. 


So again, using reduce you have two parameters. 

- accumulator - callback function
- initial value - used during the first iteration by the accumulator callback function
```js
[].reduce(accumulatorCallbackFunction, initialValue)
```

**The Accumulator callback function has four parameters**
- accumulator - the value returned from the callback function after each iteration
- item - element from the array 
- index - the index for the current element being passed into the accumulator callback
- source - the original array reduce is being called on




```js
let initial = []
let callback = (accumulator, item, index, source) => {}

[].reduce(callback, initial)
```

Finally, the last bonus tip - what if you want to break out of reduce before you're done iterating through all of the items?


```js

[].reduce((build, item, index, source) => source.slice(index), 0)

```

By slicing the source array at the given index, you'll break out of the reduce functions loop - thus if you have a big data set, you can stop using computational resources once a condition is met.


---

With that, I'll close out by saying I highly recommend practicing reduce. It is the JavaScript function that I have found the absolute most use out of. So many times, reduce has been the solution to solving complex coding challenges in a concise and to the point way.

For demo's on every single `Array.reduce` concept we covered here. Checkout the screencast I created - we dive deep into reduce. We start from simple and build up to eventually cover all of the examples shared in this post. 


{% youtube WGleM3FeZmU %}


Thanks for tuning in, and if you have any comments - questions - or concerns, the comment section is right below :) 

[Clean Code Studio](https://cleancode.studio)
[Clean Code](https://cleancode.studio/clean-code) Clean Life
[Design Patterns](https://cleancode.studio/design-patterns)
[Algorithms](https://cleancode.studio/algorithms)
[Data Structures](https://cleancode.studio/data-structures)
[Refactoring](https://cleancode.studio/refactoring)
[Simplify](https://youtube.com/c/cleancodestudio)


---

### Still disagree with me (after reading this post)?
- **Let's talk (or debate - up to you) - comment below :)**
     - What's your opinion on JS having a best function at all? 
     - Do you have a function you think beats reduce in JS?
     - Where do you disagree with my thought process? 


---

{% user cleancodestudio %}

---

Did you know I have a newsletter? 📬

If you want to get notified when I publish new blog posts or make major project announcements.

{% codepen https://codepen.io/zhorton34/pen/BaRPYdB %}