Is "find_all" and "select" the same thing?
Categories:
Ruby's find_all
vs. select
: Are They the Same?

Explore the functionality of Ruby's find_all
and select
methods, understand their identical behavior, and learn why both exist in the language.
In Ruby, developers often encounter multiple ways to achieve the same outcome. This can sometimes lead to confusion, especially when methods appear to be exact duplicates. A common point of inquiry revolves around the Enumerable#find_all
and Enumerable#select
methods. This article will clarify their relationship, demonstrate their usage, and explain the historical context behind their coexistence.
Understanding find_all
and select
Both find_all
and select
are methods provided by the Enumerable
module in Ruby. This means they are available to any class that includes Enumerable
and defines an each
method, such as Array
, Hash
, and Range
. Their primary purpose is to iterate over a collection and return a new array containing all elements for which the given block evaluates to true
.
# Using find_all
numbers = [1, 2, 3, 4, 5, 6]
even_numbers_find_all = numbers.find_all { |n| n.even? }
puts "find_all result: #{even_numbers_find_all}"
# Using select
even_numbers_select = numbers.select { |n| n.even? }
puts "select result: #{even_numbers_select}"
Demonstrating find_all
and select
with an array of numbers.
As you can see from the example above, both methods produce the exact same output: [2, 4, 6]
. This isn't a coincidence or a subtle difference; they are, in fact, aliases for each other. This means they point to the same underlying implementation.
flowchart TD A[Enumerable Module] --> B{find_all} A --> C{select} B -- Alias Of --> C C -- Alias Of --> B B -- Returns new array --> D[Elements where block is true] C -- Returns new array --> D
Relationship between find_all
and select
as aliases within the Enumerable module.
Why Two Names for the Same Method?
The existence of two names for the same method can be attributed to Ruby's design philosophy, which often prioritizes readability and expressiveness. Different developers might find one name more intuitive or descriptive than the other in certain contexts.
Historically, find_all
was the original name, likely influenced by Smalltalk, which had a similar method. As Ruby evolved, select
was introduced, possibly to align with functional programming paradigms where 'select' is a common term for filtering collections. It also provides a clearer semantic meaning for filtering operations, as you are 'selecting' elements that meet a certain criterion.
Having both aliases allows developers to choose the name that best conveys their intent, making the code more readable for themselves and others. For instance, if you are looking for all items that match a condition, find_all
might feel more natural. If you are filtering a collection to 'select' a subset, select
might be preferred.
select
is generally preferred in modern Ruby code for its conciseness and common usage in functional programming contexts. However, using find_all
is not incorrect and will not impact performance.Practical Implications and Best Practices
Since find_all
and select
are aliases, there are no performance differences or behavioral distinctions between them. You can use either interchangeably without any impact on your program's execution. The choice largely comes down to personal preference or team coding style guidelines.
When contributing to an existing codebase, it's a good practice to follow the established convention. If the project predominantly uses select
, stick with select
. If it uses find_all
, use find_all
. For new projects, select
is often the more idiomatic choice in contemporary Ruby.
It's also worth noting that Ruby has other methods for finding elements, such as find
(or detect
), which returns only the first element that matches the condition, and reject
, which returns elements for which the block evaluates to false
.
numbers = [1, 2, 3, 4, 5, 6]
# find (or detect) - returns the first match
first_even = numbers.find { |n| n.even? }
puts "First even number (find): #{first_even}" # => 2
# reject - returns elements that DO NOT match
odd_numbers = numbers.reject { |n| n.even? }
puts "Odd numbers (reject): #{odd_numbers}" # => [1, 3, 5]
Comparing find
and reject
with select
/find_all
.