4 lesser known ways to use Ruby’s Enumerable module
Tags: ruby, devtips
Published: 2019-05-22 13:59:53

---
title: 4 lesser known ways to use Ruby’s Enumerable module
published: true
description: "Learn about endless ranges, lazy iteration, range stepping, and my personal favorite each_cons"
cover_image: https://res.cloudinary.com/dzello/image/upload/v1558533899/dev.to/tine-ivanic-679622-unsplash.jpg
tags: ruby, devtips
---

A big reason I love Ruby is how much work I can get done in just a few characters or lines of code, and ensuring that code is still easy to read for my peers. One area where this is most apparent is in dealing with arrays and hashes, also known as **enumerables** in the Ruby world. 

Any object that includes Ruby’s powerful [Enumerable](https://ruby-doc.org/core-2.6.3/Enumerable.html) module can be iterated over, traversed, manipulated, sliced and diced in various ways. This module’s flexibility leads to surprisingly terse code for complex tasks.

When [Ruby 2.6 arrived in December 2018](https://blog.heroku.com/ruby-just-in-time-compilation), it came with some new methods for Enumerable as well as other improvements to list and sequence handling. In this post, I’ll show you a few capabilities recently added to Ruby’s Enumerable as well as a few old favorites.


## Endless ranges

Ranges are a great Ruby feature that allows you to quickly create iterable ranges from numbers or letters, such as `1..10` or `('A'..'Z')`. Before Ruby 2.6, the double-dot range syntax required a start and a finish. Now, there’s an intuitive syntax to create these endless ranges—simply omit a final character after the double dots: `1..`.

Why are endless ranges useful? One obvious use case is as a clean way to generate an ever-growing list of integers:

```ruby
(1..).each do |i|
  puts i
end
# 1
# 2
# 3
# ...

```

Another unique way to use endless ranges is to use them in concert with other methods chained onto enumerable. In these cases, the range isn’t exactly endless but just ends when the conditions of the chained methods are satisfied. Let’s look at an example:

```ruby
p (1..).step(5).take(100)
# [1, 6, 11, 16, 21, 26, 31, 36, 41, 46, …. 491, 496]
```

What’s happening here? The `step(5)` method takes each fifth number from the range, which remains infinite. The `take` method takes the first 100 elements of that sequence, which now becomes finite. Using an endless range to begin the expression ensures that the latter part will work for any set of inputs. We could change the 5 or 100 to larger numbers and still get the expected result.

Tip: Ranges work with letters, too:

```ruby
p ('A'..'Z').step(2)
# ["A", "C", "E", "G", "I", "K", "M", "O", "Q", "S", "U", "W", "Y"]
```

## The `lazy` keyword

This one isn’t new to Ruby 2.6, but it is powerful and underused. Enumerables support a form of lazy iteration that helps you avoid reading entire files or sets of database records into memory when you might not need to. For example, when you only need to find the first 10 lines in a file that contain the word “jane”.


```ruby
File.open("names.txt") do |f|
  f.each_line.lazy.select { |line| 
    line.match(/jane/i) 
  }.first(10)
end
```


Although it’s only one extra method, the addition of `lazy` after `each_line` changes what happens under the hood. The entire file isn’t read into memory, as is what would happen without the lazy keyword. With lazy and `first(10)` at the end of the expression, the file is read line by line, but the reading stops as soon as 10 occurrences are found.


## Range stepping

The `step` method on a range can help you produce a subrange of every 2nd, 3rd, or nth element. Ruby 2.6 brings a bit more power and a new, shorter syntax for stepping.

First off, a new alias for step is available - `%`:


```ruby
p ((1..10) % 2)
# [1, 3, 5, 7, 9]
```


Next, there are now `first` and `last` methods that can be called on steps of ranges, which is of type [ArithmethicSequence](https://ruby-doc.org/core-2.6.0.preview2/Enumerator/ArithmeticSequence.html).


```ruby
p ((1..10) % 2).last
# 9
```


## each_cons

When you need to iterate an array of multiple **overlapping** elements at a time, `each_cons` comes in handy. This method produces sub-arrays from consecutive elements similar to slice. However, the first element of the next array is the second element of the previous. This is easiest to see with an example.


```ruby
p (1..10).each_cons(2)
# [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]]
```


`each_cons` takes an integer argument for how large each array should be.

Because strings are just arrays of characters, `each_cons` can be used to do some string processing that might otherwise be tedious. Here’s a fun example to make your strings look extra spooky:


```ruby
str = "arrays and collections are scary"
p str.chars.each_cons(2).map(&:join).join
# "arrrraayyss  aanndd  ccoolllleeccttiioonnss  aarree  ssccaarry"
```


Another, perhaps more useful way to use `each_cons` is to keep the previous and next element in context while iterating over a collection.


```ruby
primes = [2, 3, 5, 7, 11, 13]
primes.each_cons(3).each { |previous, current, next_| 
  p "#{current} is the prime number between #{previous} and #{next_}"
}
# "3 is the prime number between 2 and 5"
# "5 is the prime number between 3 and 7"
# "7 is the prime number between 5 and 11"
# "11 is the prime number between 7 and 13"
```


You can see another handy Ruby feature happening here: argument destructuring. One array is being passed to the function argument of the `each` function, but we can provide three parameters: `previous`, `current`, and `next_` to have Ruby put the 0th, 1st, and 2nd array elements into those variables automatically.


## Conclusion

We’ve just scratched the surface of what’s possible with Ruby Enumerables. Hopefully you’ve learned a few tips to tighten up your current or next codebase. Combining endless ranges, stepping, and the lazy keyword can make an entire family of loop processing use cases much easier.

If you’re interested in learning more about how to level up your Ruby code, I highly recommend the Code[ish] Podcast with Aaron Patterson and this episode about [Ruby Regexes and How open source developers will make your company stronger](https://www.heroku.com/podcasts/codeish/2-ruby-regexes-and-risk-aaron-patterson-explains-why-hiring-open-source-developers-will-make-your-company-stronger).

Thanks for reading!