Each, Map, Collect and Select
Like most people who begin learning anything complex I started my journey into Ruby by making sure I understood the basics. The each
enumerable was my first foray into quickly looping through an array or hash. It is a powerful little four letter word that saved me the trouble of creating and incrementing a counter variable.
As beginner Rubyists we probably first learned each
then map
, collect
, and select
afterwards. If you were anything like me then you may be slightly confused by the differences between them. Before we dive into map
, collect
and select
it’s worth understanding the humble each
.
Each
The each method is a powerful statement that when called upon can iterate over each element and perform some sort of function we’d like. The key with each
, however (or any enumerable really), is what it returns (i.e., what does the program give us back when the enumerable finishes doing its thing separate from what we write in the block?).
Let’s say we have an array = [1, 2, 3, 4]
and we want to to multiply each of those numbers by 10.
array = [1, 2, 3, 4]array.each do |array_element|
array_element * 10
end
>> [1, 2, 3, 4]
So we’ve created an array with the integers 1, 2, 3, 4 and used each
to iterate through each element and multiply it by 10. The each
statement went to 1 and multiplied it by 10. Then it went back in and did the same for 2 and then 3 etc.
But wait, what happened? We received a return value of >> [1, 2, 3, 4]
. We wanted >> [10, 20, 30, 40]
. It turns out each
will always return back the original array. It does not change the array in any way. We could replace array_element * 10
with puts "Please, for the love of everything good in this world do not return the original array!!! Return me instead"
and we would still get the original array returned back once each
has finished iterating through the length of the array. Note, the statement would still be printed out, however, the return value is still the original array.
Certainly there are ways around this. We can simply just create another array and push
or shovel the product of it as we iterate over it and then explicitly call the new array…
array = [1, 2, 3, 4]new_awesome_array = []array.each do |array_element|
new_awesome_array << array_element * 10
endnew_awesome_array>> [10, 20, 30, 40]
While that works just fine, we did have to do some extra work in creating a new_awesome_array
and then shovel the product into it and call it to have it returned. That’s a lot of work just to get an array of numbers multiplied by ten. Thankfully Ruby has an alternative…
Map / Collect
Ok so the title of this article is slightly misleading. It turns out map
and collect
are the exact same. Yep, they do the same thing! I’ll stick with using map
. Let’s see why map
is a better alternative to each
if we wanted a new array of numbers multiplied by 10.
array = [1, 2, 3, 4]array.map do |array_element|
array_element * 10
end>> [10, 20, 30, 40]
It looks like map
will iterate through each element, perform the block (i.e., array_element * 10
) passed in and return a new array composed of those values. The advantage of map
over each
in this scenario is that we do not have to create a new array, push values into said array and return it explicitly. Rather, map
will do that work for us!
Select
Perfect! So we have our array of numbers multiplied by 10. Now let’s say we only wanted one of those numbers, we don’t care about the rest. How do we find that? Well we could use our trusty each
enumerable, create a new array, go through each element, return the element if it’s the one we are looking for or move on if it isn’t. Or we could use select
which will go through the elements and only return the elements we want. Let’s see how that looks in code if we wanted to return only 20.
array = [10, 20, 30, 40]array.select do |array_element|
array_element == 20
end>> [20]
As our return value shows select
will go through each element and perform the block. If the block is true then the element will be selected, if it is false, it will be ignored.
So there you go! Now you know the differences between each
, map
/ collect
and select
!
Additional Notes
Some important things to note
map
returns an array of the same size as the originalselect
can return an array of a different size
TL;DR
- Use
map
when you want to do some stuff to some other stuff and want the result of that back - Use
select
when you only want certain stuff back from the original