46

Given the following array a:

a = [1, 2, 3, 4, 5]  

How do I do:

a.map { |num| num + 1 }  

using the short notation:

a.map(&:+ 1)  

or:

a.map(&:+ 2)  

where 1 and 2 are the arguments?

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
not_nil
  • 471
  • 1
  • 4
  • 5

4 Answers4

43

In this case you can do

a.map(&1.method(:+))

But only because 1 + x is usually the same as x + 1.

Here is a discussion of this practice in a performance context.

Community
  • 1
  • 1
Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
36

You can't do it like this. The & operator is for turning symbols into procs.

a = [1, 2, 3, 4, 5]  
puts a.map(&:to_s) # prints array of strings
puts a.map(&:to_s2) # error, no such method `to_s2`.

& is a shorthand for to_proc:

def to_proc
  proc { |obj, *args| obj.send(self, *args) }
end

It creates and returns new proc. As you see, you can't pass any parameters to this method. You can only call the generated proc.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
  • you are right: since array.map(&:some_method) is short hand for: class Symbol def to_proc proc { |obj, *args| obj.send(self, *args) } end end. how do you pass in the *args? – not_nil Mar 29 '12 at 20:15
  • @not_nil: you don't. Use normal block/proc. – Sergio Tulentsev Mar 29 '12 at 20:18
  • 2
    @not_nil: Ruby doesn't support point-free style for anything that goes beyond `Symbol#to_proc`, because it lacks function composition and currying. Are you coming from a functional background? – Niklas B. Mar 29 '12 at 20:22
  • @sergio, thanks for the quick reply. This was more of a academic question than a real life problem. – not_nil Mar 29 '12 at 20:22
  • 1
    This is not right. & is not just for turning Symbols into Procs. It works, as far as I know, with anything that implements a `to_proc` method. You can define `to_proc` on `Array` to do what you want. See Boris Stitnicky's answer [here](http://stackoverflow.com/questions/1217088/what-does-mapname-mean-in-ruby) – Sean Mackesey Mar 12 '13 at 19:01
  • 7
    @SeanMackesey To be more accurate, `&` does not turn a symbol or anything with `to_proc` to a proc. It turns a proc to a block. Applying `to_proc` is due to implicit class casting. – sawa Mar 13 '13 at 03:58
27

You cannot do it with map. But look at Facets' Enumerable#map_send:

require 'facets'
[1, 2, 3].map_send(:+, 1)
#=> [2, 3, 4]

Writing your own implementation is pretty straightforward:

module Enumerable
  def map_send(*args)
    map { |obj| obj.send(*args) }
  end
end
tokland
  • 66,169
  • 13
  • 144
  • 170
0

If you really need that you can use Ampex library, but I don't know if it is still maintained.

Hauleth
  • 22,873
  • 4
  • 61
  • 112