Tim Cannady

Enums

fun with enumerator methods: cycle - group_by - map

Let's take a peek at three enumerator methods. But first, a quick refresh of enumerators in general:

"An enumerator is a class which allows both internal and external iteration."

In other words, a class is considered "to be an enumerator" if it has a specific set of methods that allow for iteration. We're familiar with classes like Array and String being enumerable, but this is because they come bundled with built-in enumerable methods. Which methods, you ask? Mainly the ones that allow iteration. The most popular (as well as mandatory) is .each.

So enumerators are classes that can be iterated. Whether or not they can be iterated is up to the methods they contain. Popular classes come with them built in, but you can also make custom classes that are enumerable by adding include Enumerable during their initial definition. Now lets learn about some of the popular enumerable methods:

  • .cycle

    cycle cycles through your elements. Simple! For example, call cycle on an array, pass it a block to do something to each element of that array. It will do this. Forever. (remember to pass it an argument if you want it to just cycle n-times)

  • .group_by

    group_by groups your elements by whatever code you pass the block. Furthermore, it returns a hash. Stay with me here.

    Another way of thinking of it is that group_by creates a hash and says, "any time there's a unique output from the block, we'll save it to a new key. For every element that resulted in that unique output, we'll assign it to that key's value in an array form. This way you can group all the elements together that would have the same output when passed to the block"

    So the hash's keys come from the evaluated result passed to the block on each iteration. For example, if the block multiplies an input by three, the first key would become the output, and the next key would become the value from the next iteration. On the other hand, the hash's values are simply the value of the element that was used by the block. In other words, it's the value of each index being passed to the block. Consequentially, the hash's value can have more than one value (in array-form), one for each value that results in the same output when passed to the block.

    In the code below we call group_by on the range of numbers from one to six. Look to the block and we'll notice that for every index (every number in the range), we simply multiply it by three. We've done this plenty of times with .each. But the difference is the way the output is saved. In the case of group_by, the output is saved in a hash. We see the keys become the values the block evaluated to (3,6,9 etc). The values are each element that resulted in the value that we just assigned to the keys. For example, the first pair has a value of one. When we multiply the value of the first index by three, the output is three. So the key becomes three, and the value is 1 (the value that was passed ot the block):

  • .map

    map is a little easier than group_by. The quickest way to understand map is to liken it to each. Recall that each does something to each element of the object it's called on, and it returns a new object. In other words, each isn't destructive. Map does just this but is destructive.

  • There's plenty of other enumerator methods to do all the tricks you need. Be sure to check out the Ruby Docs for more!