My smiling face

Paul Dynowski

Fledgeling Web Developer, All-Around Swell Guy

Facebook Twitter GitHub LinkedIn Email

Enumberable methods

Digitally manipulating your collections - and your emotions

Nov 12, 2015

Manipulating my what, now?

Your collections. Basically, your arrays and hashes. We've discussed those before, remember? Anyway, "collection" is a general way to refer to arrays or hashes in Ruby (in other languages, you might get to include lists, maps, or dictionaries as types of collections).

Collections, check. Now, what's this Enumerable thing?

Enumerable is a module which provides all sorts of functionality to the collections in Ruby - basically, it's a defined set of methods that the collections implement and allow you to do some neat things to the collections. (Note that you can also write your own classes that implement Enumerable, but that's a bit deeper into the pool than we're ready to wade just yet.)

Like what?

Well...there's a full list of Enumerable methods in the Ruby documentation. In general, though, there are methods that will return a specific value from the collection (find, etc), methods that will return arrays of values that meet certain conditions from your collection (select, etc), methods that perform an operation on each element of a collection and return the modified collection as a result (map, etc), and methods that combine all of the elements of a collection into a single value (reduce). It's this last one that I am going to elaborate on.

So, what does reduce do?

Okay, first things first. reduce is also known as inject. Why? Because Ruby tries to be friendly to people coming from other programming languages, and reduce and inject both did similar things in previous languages, so Ruby implements them both. Not a big deal, just remember that any time reduce is used in examples below, you can replace it with inject without changing the result.

Now, to begin with the definition from the docs:

[reduce] combines all elements of enum by applying a binary operation, specified by a block or symbol that names a method or operator
In English, this means that reduce tracks a single value, and modifies that value by successively combining it with each value in your collection, in a manner which you define. Note that the result of each iteration is the input to the next iteration. In this manner, after you've iterated through your entire collection, you've reduced it to a single value.

Okay. How do I set this magical method up, then?

Oh, there are just so many ways to do it. Well, okay, there are four, which fall into two general categories: ways where you're setting up a basic, repeated use of an arithmetic operator, and ways where you're setting up a block of code to do the operation. Add the ability to set an initial value or not, and you get four, as demonstrated here (all four methods should return the same result):
a.reduce(:+) a.reduce(0,:+) a.reduce {|total,n|
total + n
}
a.reduce(0) { |total,n|
total + n
}

So, what will these do?

In this case, we've set up the reduce method to add up all the elements of our array. In examples two and four, we've additionally set the starting value of the tracking variable to zero. In cases one and three, the tracking variable will be set by the value of the first iteration. So, we'll take as an example a simple array: [2,4,6,8,10]. Now, on the first iteration, the current value will be 2. In the examples where we've defined the initial value, we will perform the operation 0 + 2, and store the value for the next iteration. In the other examples, the first value will simply be set to 2. Now, on the second iteration, our stored value is 2, and we pull 4 as the current value, and add them together to get 6, which will be our value for the third iteration, and so on. In tabular form:

Pass12345
Curr246810
Total26122030
And in the end, our array will be reduced to a single value: 30.

Can it do anything else?

Of course it can - if you define the code block correctly, you can use reduce to find the max or min value in an array of numbers, the longest string in an array of strings, or anything else that can be summed up in a single value.

And thus ends my basic discussion of the wondrous reduce method. Please let me know if I can clarify any issues, or if I've inadvertently missed or misstated pertinent information.