70

Possible Duplicate:
Shorter way to pass every element of an array to a function

I know this will work:

def inc(a)
  a+1
end
[1,2,3].map{|a| inc a}

but in Python, I just need to write:

map(inc, [1,2,3])

or

[inc(x) for x in [1,2,3])

I was wondering whether I can skip the steps of making a block in Ruby, and did this:

[1,2,3].map inc
# => ArgumentError: wrong number of arguments (0 for 1)
# from (irb):19:in `inc'

Does anyone have ideas about how to do this?

Community
  • 1
  • 1
Hanfei Sun
  • 45,281
  • 39
  • 129
  • 237
  • http://stackoverflow.com/questions/13834846/shorter-way-to-pass-every-element-of-an-array-to-a-function/13834860#13834860 – oldergod Dec 19 '12 at 04:45

2 Answers2

106

According to "Passing Methods like Blocks in Ruby", you can pass a method as a block like so:

p [1,2,3].map(&method(:inc))

Don't know if that's much better than rolling your own block, honestly.

If your method is defined on the class of the objects you're using, you could do this:

# Adding inc to the Integer class in order to relate to the original post.
class Integer
  def inc
    self + 1
  end
end

p [1,2,3].map(&:inc)

In that case, Ruby will interpret the symbol as an instance method name and attempt to call the method on that object.


The reason you can pass a function name as a first-class object in Python, but not in Ruby, is because Ruby allows you to call a method with zero arguments without parentheses. Python's grammar, since it requires the parentheses, prevents any possible ambiguity between passing in a function name and calling a function with no arguments.

pyrmont
  • 225
  • 5
  • 12
Platinum Azure
  • 45,269
  • 12
  • 110
  • 134
  • I think another reason we cannot write `map(:inc)` directly is Ruby is a purer OO language. – halfelf Dec 19 '12 at 05:00
  • Ack, forgot the `&` token, sorry. Fixed. – Platinum Azure Dec 19 '12 at 05:04
  • 5
    `Ruby will interpret the symbol as an instance method name and attempt to call the method on that object.` => Your mentioning of instance method is not correct, or is at least not clear enough. `&` converts what it is attached to into a block if it is a Proc. If it is not Proc, then it applies `to_proc`, in this case `Symbol#to_proc`. – sawa Dec 19 '12 at 06:03
  • @sawa: Very true. I couldn't think of a way to explain that concisely without sacrificing clarity; if you have a good reference, please feel free to edit my answer reflecting that. – Platinum Azure Dec 19 '12 at 21:53
  • 2
    Please fix the link – Joe Eifert Oct 25 '16 at 14:53
  • Replaced original link with link to Internet Archive. – pyrmont Jul 20 '18 at 03:08
12

Does not answer your question but if you really just want to increment all your variables, you have Integer#next

4.next
#=> 5

[1,2,3].map(&:next)
#=> [2, 3, 4]
oldergod
  • 15,033
  • 7
  • 62
  • 88