BigBinary Blog

We write about Ruby on Rails, React.js, React Native, remote work, open source, engineering and design.

Ruby 3.1 adds Enumerable#compact and Enumerator::Lazy#compact

This blog is part of our Ruby 3.1 series.

We are familiar with the compact method associated with arrays. The compact method returns a copy of the array after removing all nil elements.

Ruby 3.1 introduces the compact method in the Enumerable module. Now we can use the compact method along with the Enumerator and Enumerator::Lazy classes which include the Enumerable module.

Before Ruby 3.1

1=> enum = [1, nil, 3, nil, 5].to_enum
2=> #<Enumerator: ...>
3
4=> enum.compact
5=> NoMethodError (undefined method `compact' for #<Enumerator: [1, nil, 3, nil, 5]:each>)
6
7=>  enum.reject { |x| x.nil? }
8=> [1, 3, 5]

After Ruby 3.1

1=> enum = [1, nil, 3, nil, 5].to_enum
2=> #<Enumerator: ...>
3
4=> enum.compact
5=> [1, 3, 5]

We can access the compact method to remove all nil occurrences from any classes where we include the Enumerable module.

1class Person
2  include Enumerable
3
4  attr_accessor :names
5
6  def initialize(names = [])
7    @names = names
8  end
9
10  def each &block
11    @names.each(&block)
12  end
13end
14
15=> list = Person.new(["John", nil, "James", nil])
16=> #<Person:0x0000000101cd3de8 @names=["John", nil, "James", nil]>
17
18=> list.compact
19=> ["John", "James"]

Similarly, lazy evaluation can be chained with the compact method to remove all nil entries from the Enumerator collection.

1=> enum = [1, nil, 3, nil, 5].to_enum.lazy.compact
2=> #<Enumerator::Lazy: ...>
3
4=> enum.force
5=> [1, 3, 5]
6
7
8=> list = Person.new(["John", nil, "James", nil]).lazy.compact
9=> #<Enumerator::Lazy: ...>
10
11=> list.force
12=> ["John", "James"]

Here's the relevant pull request and feature discussion for this change.

Ashik Salman in Ruby 3.1
April 6, 2021
Share

Subscribe to our newsletter