How can we search through lists like objects and arrays?
As a beginner in Ruby, I struggled differentiating methods like .select and .find. They can be confusing if you do not have the knowledge of when to use them. I hope this post can help you understand the differences between the two.
The .find method
This Ruby method iterates through an array and gives you the first match for which the expression within a block returns true.
For example :
>> [1,2,3,4,5,6,7].find { |x| x.between?(3,4) }=> 3>> [1,2,3,4,5,6,7].find { |x| x.between?(3,6) }=> 3>> [1,2,3,4,5,6,7].detect { |x| x.between?(3,7) }=> 3>> [1,2,3,4,5,6,7].detect { |x| x.between?(2,7) }=> 2
As you can see in the example above, we are iterating on arrays. Let?s say in the first example, we are telling Ruby ?Here is an array with some numbers, please iterate through each number and give me the number that it is between 3 and 4.? Ruby will do its job and will find me the first number that it is true to the condition given. In this case, it will be the number 3. Now, what happened if the value is not found? The iterator will return NIL.
.detect is another method which is an alias for .find. Both methods return the same result.
The .select method
The .select method iterates on an array or hash and returns an array or hash (depending on the datatype) of all values that evaluate as true given a block of code. This method is great when you want to filter a list and only return values that match certain conditions. In other words, it returns more than 1 element, as supposed to the find method discussed previously. You can use .select with arrays and hashes. That means that if you use .select with an array, it will return an array. Otherwise, if you use a hash, the return value will be a hash.
Example:
[1,2,3,4,5].select { |num| num.even? } #=> [2, 4]
In this example, we are iterating on an Array, so the return value will be an Array! Each element was subjected to the .even? method, and out of all elements, 2 and 4 return true. (Example of .select on a Hash below)
.find_all is another method that can also be an alias for .select. BUT you have to be careful with this method because it works differently on an array and on a hash. Then, let?s see what the deal is!
Enumerable#find_all and Enumerable#select run on the same code. This means that in Ruby, we call an object an enumerable when it describes a set of items and a method to loop over each of them. This is the reason why using both methods will yield the same result. The same happens for Range, as it uses as well enumerable implementation.
Now, what happens with .select on a hash?
In this case, the .select method is returning a new hash instead of an array.
Let?s see the example:
array = [1, 2, 3, 4, 5, 6]hash = {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6}array.select{|x| x.even?} # => [2, 4, 6]array.find_all{|x| x.even?} # => [2, 4, 6]hash.select{|k,v| v.even?} # => {:b=>2, :d=>4, :f=>6}hash.find_all{|k,v| v.even?} # => [[:b, 2], [:d, 4], [:f, 6]]
In the example above, you can observe that .find_all gives an array even though you are iterating on an Array or a Hash. .select instead gives us an Array or a Hash.
They are similar methods, but it is important to know how each works, because it is possible that the subtle differences between the two may cause an issue with your code.
Bravo! By the end of this post, you should be able to know how the select and find methods work. It may not seem that difficult, but I personally struggled with these methods until I did more research on them. Be sure to go over the examples that were covered, so you can truly understand the power of these methods.
Sources:
- Ruby.org-find: Ruby-doc description of find method.
- Ruby.org-select: Ruby-doc description of select method.
- StackOverflow-Is ?find_all? and ?select? the same thing?: Discussion between find_all and select methods.