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

Ashik Salman

Ashik Salman

April 6, 2021

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

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

=> enum.compact
=> NoMethodError (undefined method `compact' for #<Enumerator: [1, nil, 3, nil, 5]:each>)

=>  enum.reject { |x| x.nil? }
=> [1, 3, 5]

After Ruby 3.1

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

=> enum.compact
=> [1, 3, 5]

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

class Person
  include Enumerable

  attr_accessor :names

  def initialize(names = [])
    @names = names
  end

  def each &block
    @names.each(&block)
  end
end

=> list = Person.new(["John", nil, "James", nil])
=> #<Person:0x0000000101cd3de8 @names=["John", nil, "James", nil]>

=> list.compact
=> ["John", "James"]

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

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

=> enum.force
=> [1, 3, 5]


=> list = Person.new(["John", nil, "James", nil]).lazy.compact
=> #<Enumerator::Lazy: ...>

=> list.force
=> ["John", "James"]

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

If this blog was helpful, check out our full blog archive.

Stay up to date with our blogs.

Subscribe to receive email notifications for new blog posts.