Reducing Enumerable — Part One: The Journey Begins

Title slide for “Reducing Enumerable — An Illustrated Adventure”

Behold! The lemurs have chosen to appear on a text-based medium, bringing with them the entirety of the illustrated content from “Reducing Enumerable — An Illustrated Adventure”.

If you wish to see the full RubyConf version of the talk, you can find it here:

As this was a very image intensive and story driven presentation, we’ll be splitting this up into multiple articles for the sake of digestibility.

Table of Contents

  1. The Journey Begins
  2. Chartreuse — The Master of Map
  3. Indigo — The Master of Select
  4. Violet — The Master of Find
  5. Cerulean — The Master of Tally By
  6. A Final Lesson from Scarlet

Next >>

Meet Red

Red waving hi

Meet Red, the lemur. He’s a student of the great Master Scarlet, learning the ways of reduce.

He’s been practicing for quite some time now on summing numbers and learning the ways of functional programming.

By this point he believes himself to be quite adept at it, if not ready to attempt the mastership trials himself.

Red with a hammer, thinking about reducing things

Now Red absolutely adores reduce, and especially reducing large stacks of numbers into simple sums. He’s gotten quite good at it in fact.

Red dreaming about reducing big stacks of numbers

So good in fact that he’s become rather obsessed with it, and he’d like to show us the basics of how reduce works. Shall we take a look?

A Look into Reduce

Now reduce is a very interesting function in Enumerable, and very frequently it’s hard to understand what it’s doing.

Let’s take a bit of a look into how it works.

list of 1, 2, and 3 sums to 6

Reduce, in the case of a sum, takes in a list of numbers and returns back the sum of those numbers.

[1,2,3].reduce(0) { |a, v| a + v } # => 6

The code for this might look something like this, but that’s a bit hard to understand, so let’s break it down a bit, shall we?

Accumulators

Looking at the accumulator, 0, represented as a in the function and returned with the value 6

We start with an accumulator. An accumulator starts as the first argument to reduce, and in this case it’s 0. Why 0? If we add anything to 0 we get back that number. That makes it a good “empty” element.

When the list is empty we get back our empty element!

We’ll see our accumulator show up as a throughout this article.

Lists and Values

Looking at the list of 1, 2, and 3 represented as v in the function

Next up is our list, which will show up as v throughout this article. Every element of our list will be iterated over while reducing, going into the function as v.

Joining Values and Accumulators

Looking at the plus operator used to join an accumulator and a value to make a new accumulator

Last, and perhaps most importantly is how we join our value and our accumulator together to make a new accumulator. In this case, +.

Now the interesting thing here is that how we join things together impacts our empty value as well. It would make very little sense to join any number with multiplication if our supposedly empty value is 0, no?:

[1, 2, 3].reduce(0) { |a, v| a * v }
=> 0

It would always return 0! Instead we’d want to use 1 for this particular pairing.

All Together Now

0 + 1, 2, 3

So all together we might have something that looks a bit like this. Reducing the list of 1, 2, 3 into the starting value 0 using + to join values together.

More commonly that might look something like this:

0 + 1 + 2 + 3

But how exactly does it work? How do we trace that flow of data? Let’s take a look into that.

How Reduce Reduces

Each step of reduce, as explained in the below text

For every loop of reduce, we pass into the function our accumulator and our next value. Whatever is returned from that function becomes the new accumulator on the next run of reduce.

  1. We start out with an initial value of 0 and add 1 to it, giving us a new accumulator of 1.
  2. That means next loop we start with 1 and add to it the next value in our list, 2, giving us 3.
  3. On our last loop we have an accumulator of 3 and a last value of 3.
  4. Now that reduce has run out of numbers to, well, reduce, it returns the final accumulator it had. In this case, our answer is 6.

What is Reduce?

Explaining the core elements of reduce, as mentioned in the text below

Reduce is a way to take a list of many things and reduce it into one thing using an initial value, and a way to join values together to make a new accumulator.

Masters of Functional Programming

Red dreaming of himself as a wise master with grand powers

Surely now this makes us masters of Functional Programming, drinkers of the fount of knowledge, wise beyond our years and powerful beyond mortal reckoning! The full powers of Ruby are at our fingertips, and nothing can stop us!

Well, except for one thing…

Enumerable#sum

[1,2,3].sum # => 6

Ruby 2.4+ introduced a new function, sum, which does about the same thing.

Realizing this, Red is noticeably distraught. Everything he had learned from before now seemed to be completely irrelevant in the face of this new function, which made him ask a very hard question:

Is reduce unnecessary?

Was reduce unnecessary? He decided to go to the one source he knew would have an answer to his question, his master Scarlet.

Asking for Help

Red wrote a letter, asking her quite simply:

Red writing letter to master: “Does sum kill reduce? — Red”

Does sum kill reduce? With the letter sent, Red began to pace, waiting eagerly for a reply. Finally, it came, his master had replied to his letter!

Red receiving sealed envelope from his master.

…and inside the letter it said simply: “Come to me if you wish to learn”.

With that, Red decided it was time to go on an adventure.

Journey to Master Scarlet

Red journeying to see his master, as explained in below text.

So Red ventured through the plains and across the hills, into the mountains past the forests and creeks, and there before him was a sign. The sign pointed to the castle of his master, tucked away behind the clouds, high above the mountain peeks.

Around it giant balls of light circled, as if to invite those who had ventured to find her.

With that Red pressed on, and entered the castle.

Master Scarlet

Red explaining his predicament to his master.

So Red met master Scarlet in her castle, and began to tell her of all the things he had learned and done in his time since leaving. He had learned much and grown, but still he felt as if something were missing, something only she could show him, so Red asked:

“Wise master, does sum make reduce useless?” asked Red.

Scarlet enlightening Red

“Ah Red. Consider, for a moment perhaps, that you can do more than just summing with reduce. What if we used subtraction? Multiplication? Division? What if we don’t use numbers at all?” replied Scarlet.

Scarlet showing Red an empty array and a joining function, push

“Perhaps instead we have an empty array, and push to add elements to it. What could one do with this?” asked Scarlet.

Scarlet sending Red off on an adventure

“I know just the thing. You’ll find three masters in the land of Enumerable. Go out and learn from them about their functions, and see if you can figure out how you may use reduce to do the same.”

With that, Scarlett left Red with much to think on, and a map to help him on his way.

Into the Land of Enumerable

Red looking at map, looking over entire land of Enumerable

With that he was off to the corners of the map, to learn from the masters he would find there. The land of Enumerable was a vast place, full of surprises and curiosities, but with the help of his master and his trusty map, Red would find exactly what he needed.

Red with a close up of the map with a path drawn to “map”

The first master Red was to meet was the master of Map, Chartreuse.

Next >>