Programming - DevOps - Project Management - Information Security

Enumerator#each_cons

If you are a Ruby programmer and you haven’t found a use for
Enumerable#each_cons, you just probably haven’t thought about it yet.
— Michael Feathers (@mfeathers)

Well, Ruby is a great language, with a lot of nice surprises tucked away
in its dustier corners. The Enumerator class is certainly a common one
to reach for when solving problems, but I can honestly say I’ve never
needed the Enumerator#each_cons method. After seeing Michael’s
tweet, I took a look to see what it does.

The method definition says:

each_cons(n) {...} → nil
each_cons(n) → an_enumerator
Iterates the given block for each array of consecutive <n> elements.
If no block is given, returns an enumerator.

On the surface, it looks like just another way to specify an array
slice. Not so! The #each_slice method will return chunks of n
elements, but #each_cons actually returns a sliding window of
elements. Consider the following:

What’s interesting is that the output of #each_slice will return
non-overlapping blocks of Enumerable elements, while #each_cons shows
all possible consecutive blocks from the Enumerable object. It’s as if
the method slides a window of n elements across the length of an
array, moving the starting index of the window up by exactly one element
each time.

Another non-obvious property is that #each_slice will happily return
an array smaller than the specified value if it runs out of Enumerable
elements to process, while #each_cons always returns the requested
length unless it returns nil. For example:

If you want to know all the various ways that elements of an array can
be arranged together, Array#combination or Array#permutation
seem like they’d be more intrinsically useful. On the other hand, this
method is clearly intended for segmenting an Enumerable, but the
real-world usefulness of doing so eludes me.

I always enjoy exploring odd corners of Ruby, and hope you’ve enjoyed
this little tour of Enumerable#each_cons. If you can think of a
practical use for it, please leave a comment below.