**.reduce** is a confusing enumerable. But I'd like to think that what makes it confusing can also make it a powerful tool.

Today I'd like to dispel some of the confusion, and also show some examples of *versatile* of a method it is.

## What does .reduce do?

Let's start with an easy example: Let's say we have an array of numbers that we want to *reduce* down to a single value, it's sum. (Let's also say a powerful, Ruby-based wizard took away our **.sum** method)

```
array = [1, 1, 1]
array.reduce(0) {|sum, i| sum + i} #=> 3
```

OK. Let's unpack what the code just did, above.

###
**.reduce** as an *accumulator* method

Above, we gave **.reduce** a single parameter (`reduce(0)`

), as well as named two variables within the pipes (`|sum, i|`

). Let's call the parameter the **start** value, and the two variables the **memo**, and **current_element**, respectively.

```
array.reduce(start) {|memo, current_element| statement}
```

**current_element** is fairly straightforward; it is the current value of the array you are iterating over.

**memo** stores the return value of the previous iteration.

**start** provides an optional starting-point, by passing it's value as the first value of **memo**.

Let's look at the above example again, but this time at *each iteration* that is happening:

```
array = [1, 1, 1]
array.reduce(0) {|sum, i| sum + i}
# 1st: 0 + 1 #=> 1
# 2nd: 1 + 1 #=> 2
# 3rd: 2 + 1 #=> 3
```

Each iteration is adding the **sum** value to the **current_element**, then saving that return as the next value for **sum**. At the end of the iteration, the final value of **sum** is returned!

Before we move on... remember how I said that the parameter value was optional? If we don't pass in the **start** value, the method will take `array[0]`

for the first value of **memo**, and start iterating with `array[1]`

!

```
array = [1, 1, 1]
array.reduce {|sum, i| sum + i} #=> 3
```

Now that we understand the basics, let's get into some of the fun *versatility* that **.reduce** has to offer.

## Using conditional logic to control our returns

Well, I guess I forgot my repellent. The pesky wizard came back and this time he took our *max_by* method... How am I supposed to find the largest name out of this group of names?

```
names = ["Gandalf", "Saruman", "Radagast"]
```

Well let's see what **.reduce** can do!

```
names.reduce do |longest, current|
if current.length > longest.length
current
else
longest
end
end #=> 'Radagast'
```

By implementing some control-flow, we can look at each value of the `names`

array, and either return the `current`

if it's longer than the `longest`

, or keep the same value of `longest`

for the next iteration.

This could be written more elegantly as well:

```
names.reduce do |longest, current|
current.length > longest.length ? current : longest
end #=> 'Radagast'
```

Ternary operators make up some of the bread-and-butter of **.reduce** control flow.

There is a glaring flaw in our method, however. What happens when two or more names are of the same length?

```
names = ["Bronson", "Dave", "Swanson", "Steve", "Johnson"]
```

Our current **.reduce** method will only return the *first* longest name, since no subsequent values will pass `true`

for `current.length > longest.length`

!

##
Returning multiple values with **.reduce**

Remember how we can pass an optional **start** parameter to our method? Well we can actually use this to our advantage to create a **.reduce** method that returns an array of multiple responses!

```
names = ["Bronson", "Dave", "Swanson", "Steve", "Johnson"]
names.reduce([""]) do |long_names, current|
if current.length > long_names[0].length
[current]
elsif current.length == long_names[0].length
long_names << current
else
long_names
end
end #=> ["Bronson", "Swanson", "Johnson"]
```

To break this down, we need to keep the output consistent across each iteration, so since we want an array of strings, we put an array with an empty string as the **start** value. After each iteration, we can either start a new array if `current`

is greater than the previous longest name, we can add to the array if `current`

is the same length as the previous longest name, or we can move on, by returning the `long_names`

array in it's current form.

**.reduce** is a powerful tool, so I hope this helped make it more clear how it works. There's still power yet to be explored with this enumerable, so as a cliffhanger, I'll leave you with another way to refactor the *sum* example from earlier:

Instead of `array.reduce {|sum, i| sum + i}`

...

Why not try `array.reduce(:+)`

?

## Top comments (0)