Gwater17 Gwater17 - 7 months ago 13
Ruby Question

Converting array using procs and symbols

I'm working my way through Ruby's Codecademy course and I'm up to here https://www.codecademy.com/en/courses/ruby-beginner-en-L3ZCI/1/6?curriculum_id=5059f8619189a5000201fbcb#

The correct code (that I don't understand) to convert the array of numbers into an array of strings is posted below.

numbers_array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

strings_array = numbers_array.map(&:to_s)


I've been looking through the forums and googling and at this point I'm still confused what the heck is going on in this code.

I'm confused by
:to_s
because
to_s
means to convert to strings and
:
stands for symbols. Does
:to_s
convert stuff into symbols or strings?

I'm confused by
&
too. I get that the
&
sign makes the block that follows it into a proc, but here it's the colon for symbol and the method to convert to a string rather than a block that follows the
&
symbol.

I'd really appreciate any help!

Answer

What happens is that the syntax &:to_s is another way constructing a block that calls the method that matches the symbol, on every item in the array. In your case, it is basically the same as writing:

strings_array = numbers_array.map { |number| number.to_s }

Here is another example:

strings_array = numbers_array.map(&:to_f)
# Same as
strings_array = numbers_array.map { |number| number.to_f }

For further explanation regarding the & sign, look at how you would define a method that accepts a block as an argument.

def map(&block)
  # ....
end

Now look at the different ways we could invoke this method that all will yield the same result.

# Block using bracket notation
map { |n| n.to_i }

# Block using do ... end notition
map do |n|
  n.to_i
end

# When using ampersand, ruby will try to treat the following as a 
# proc and use to proc as the block for the method. If we pass a proc
# to it, then no problem.
p = proc { |n| n.to_i }
map(&p)

# When using ampersand with a symbol (or any other non-proc objects), 
# ruby will try to call the to_proc method on the object and use that
# as a block. And in the scenario of passing a symbol, the Symbol 
# object will return a proc that calls the method that matches the symbol.
:to_i.to_proc => #<Proc:...>
map(&:to_i)