Ruby - map()
Hi, today we will see how the map function does work. We will recode one as well as the other function that the map function can call.
You can use the map function like this :
main.rb
[1, 2, 3].map { |elem| elem * 2 }
=> [2, 4, 6]
[1, 2, 3].map(&:to_s)
=> ["1", "2", "3"]
You can’t give map both a block and an argument, you have to choose.
In the first case, the map function will browse the array and multiply each elements of the array by 2. On the second case, the map function will also browse the array, but will call for each element the to_s function. How the eck is that possible ?
Recoding map
Just to make sure we understand everything we can recode the function. Here is our implementation of map :
map.rb
class Array
def map(&block)
result = []
self.each { |elem| result << block.call(elem) }
result
end
end
Okay, let’s see what do we got here ? First we use open class technique to redefine the native map function. We iterate on the array using the self keyword and the each function. Then we add the result of block.call(elem)
in result and return when all the iteration are done. What the eck does block.call(elem)
mean ?
- Explicit block : In ruby, when you use the
&
symbol as parameter you specify that explicitly this parameter will be a block.
The map function in ruby call the to_proc function trying to convert the block variable (:to_s
) into a proc.
As stated by the doc of ruby, this is the to_proc
definition of the function of the Symbol class :
returns a Proc object which respond to the given method by sym.
We now know that block.call is a proc calling the to_s function on the parameter given. In other word the to_s function is called on each elem of the array through a proc.
Let’s recode the to_proc method of the Symbol’s class
class Symbol
def to_proc
proc { |obj, args| elem.send(self, *args) }
end
end
Okay, you think I am crazy but I can assure you it’s not that difficult. block.call is … called by the map function (map.rb
), passing elem
(one of the object when iterating the array) as parameter into the to_proc
function of the symbol class as the obj
parameter, and from here we call the send function with self
which is equal to :to_s
and guess what ? Have you ever seen a line of code like this : 1.send(:to_s)
yep ! You do ! And that’s how we get a result like ["1", "2"]