How do I pass an argument to array.map short cut? [duplicate]
Asked Answered
D

4

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?

Dael answered 29/3, 2012 at 20:5 Comment(2)
Cheating: [1, 2, 3, 4, 5].map(&:next) # => [2, 3, 4, 5, 6]Chloro
You might be interested in Ruby's Enumerators.Oldtime
P
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.

Pilliwinks answered 29/3, 2012 at 20:8 Comment(6)
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?Dael
@not_nil: you don't. Use normal block/proc.Pilliwinks
@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?Needlework
@sergio, thanks for the quick reply. This was more of a academic question than a real life problem.Dael
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 hereDecree
@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.Foreclosure
A
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.

Arsenical answered 29/3, 2012 at 21:44 Comment(0)
P
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.

Pilliwinks answered 29/3, 2012 at 20:8 Comment(6)
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?Dael
@not_nil: you don't. Use normal block/proc.Pilliwinks
@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?Needlework
@sergio, thanks for the quick reply. This was more of a academic question than a real life problem.Dael
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 hereDecree
@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.Foreclosure
D
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
Deprecatory answered 29/3, 2012 at 20:33 Comment(0)
S
0

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

Stentor answered 13/5, 2013 at 13:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.