Ruby's Map and The & Operator

January 31, 2013

My mentor mentioned Ruby’s map and & operator during a quick lunchtime chat today, so I decided to revisit this helpful and yet often unknown combination.

Let’s start with a simple example–a map that iterates through an array of items and returns an array with modified values:

[1, 2, 3].map{ |number| number.to_s }
=> ["1", "2", "3"]

Works as I was intending! Each element is converted to a string using to_s. But there’s another way to write this by combining map and the & operator:

[1, 2, 3].map(&:to_s)
=> ["1", "2", "3"]

However, I found I broke it if I tried to describe a custom method after the &:

[1, 2, 3].map(&+=1)
=> SyntaxError: (irb):23: syntax error, unexpected tOP_ASGN

Well, that’s clearly not what I was hoping for. The reason this doesn’t work is because Ruby is expecting a block of code or a Proc (in which case it will turn the Proc into a block of code). So, I could just pass in a new, custom proc to return what I want and it will work:

[1, 2, 3].map(&Proc.new{|x| x + 1})
=> [2, 3, 4]

Unfortunately, this is just making this line of code longer without any real benefits so I’d never write it like this.

So why was I passing in a symbol (:to\_s) in the first example? The symbol (:to\_s) is simply referring to the method (.to\_s). You can use any available methods, or define your own to pass into the map:

1.9.3p362 :001 > def foo
1.9.3p362 :002?>   self + 1
1.9.3p362 :003?> end
=> nil 
1.9.3p362 :004 > [1, 2, 3].map(&:foo)
=> [2, 3, 4]

One thing to remember, however, is that if your function requires any argument(s), then your map won’t work:

1.9.3p362 :005 > def foobar(x)
1.9.3p362 :006?>   self + x
1.9.3p362 :007?> end
=> nil 
1.9.3p362 :008 > [1, 2, 3].map(&:foobar)
ArgumentError: wrong number of arguments (0 for 1)
  from (irb):5:in `foobar'
  from (irb):8:in `map'
  from (irb):8
  from /Users/rylan/.rvm/rubies/ruby-1.9.3-p362/bin/irb:16:in `<main>'
1.9.3p362 :009 > [1, 2, 3].map(&:foobar(1))
SyntaxError: (irb):9: syntax error, unexpected '(', expecting ')'

Happy mampersanding! And yeah, I totally made that word up.

Sources: