What's the Difference Between "Array#select!" and "Array#keep_if" Methods in Ruby?

Both, Array#select! and Array#keep_if, mutate (or modify) the original array and remove values from it that do not match the specified condition (as provided in its block — i.e. the code between {...}). However, they differ in terms of their return values:

  • Array#select! — returns the updated array if something was removed, or returns nil otherwise;
  • Array#keep_if — returns the array (regardless of whether a value was removed from the original array or not);

To demonstrate this, let's suppose you are trying to keep all odd numbers in an array of integers that has no even numbers:

numbers = [1, 3, 5, 7]
result = numbers.select! { | item | item.odd? }

# returns `nil` because nothing was removed
print result #=> nil

# original array is unchanged:
print numbers #=> [1, 3, 5, 7]
numbers = [1, 3, 5, 7]
result = numbers.keep_if { | item | item.odd? }

# returns the array
print result #=> [1, 3, 5, 7]

# original array is unchanged:
print numbers #=> [1, 3, 5, 7]

As you can see from the examples above, when Array#select! does not modify the array, it returns nil, whereas, in the same instance, Array#keep_if returns the unchanged array.

When either of these methods modify the original array, they have the same output (which is the modified array):

numbers = [1, 2, 3, 4]
result = numbers.select! { | item | item.odd? }

# returns the changed array
print result #=> [1, 3]

# original array is changed:
print numbers #=> [1, 3]
numbers = [1, 2, 3, 4]
result = numbers.keep_if { | item | item.odd? }

# returns the changed array
print result #=> [1, 3]

# original array is changed:
print numbers #=> [1, 3]

This post was published by Daniyal Hamid. Daniyal currently works as the Head of Engineering in Germany and has 20+ years of experience in software engineering, design and marketing. Please show your love and support by sharing this post.