Rails 6 adds Array#extract!


Rails 6 has added Array#extract!. It returns the array elements for which the passed block returns true and modifies the original array with remaining elements. If no block is given, an Enumerator is returned instead.

Before

Lets say we want to separate out odd and even numbers from an array. We can achieve this by using select, reject or partition.

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
odd_numbers = numbers.select { |number| number.odd? } 
# => [1, 3, 5, 7, 9]
numbers
# => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
numbers - odd_numbers
# => [0, 2, 4, 6, 8]
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
even_numbers = numbers.reject { |number| number.odd? } 
# => [0, 2, 4, 6, 8]
numbers
# => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
numbers - even_numbers
# => [1, 3, 5, 7, 9]
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
odd_numbers, numbers = numbers.partition { |number| number.odd? } 
# => [[1, 3, 5, 7, 9], [0, 2, 4, 6, 8]]

And if we use select!, reject!, delete_if or keep_if then:

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
odd_numbers = numbers.select! { |number| number.odd? } 
# => [1, 3, 5, 7, 9]
numbers
# => [1, 3, 5, 7, 9]
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
even_numbers = numbers.reject! { |number| number.odd? } 
# => [0, 2, 4, 6, 8]
numbers
# => [0, 2, 4, 6, 8]
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
even_numbers = numbers.delete_if { |number| number.odd? } 
# => [0, 2, 4, 6, 8]
numbers
# => [0, 2, 4, 6, 8]
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
odd_numbers = numbers.keep_if { |number| number.odd? } 
# => [0, 2, 4, 6, 8]
numbers
# => [0, 2, 4, 6, 8]

Array#extract!

We can now use Array#extract! in Rails 6 to achieve this in a simpler and more readable way:

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
odd_numbers = numbers.extract! { |number| number.odd? } 
# => [1, 3, 5, 7, 9]
numbers 
# => [0, 2, 4, 6, 8]

As you see, extract! returns elements which are odd, and sets numbers with elements which are not odd.

This comes in pretty handy when we want to handle
both extracted elements and remaining elements differently.