Question

In particular, using inject, the following scripts,

  • puts (1..5).inject {|x, y| x * y} and
  • puts (1..5).inject(:*),

both have output 120 as I expected.

However, the script

print [[1,2], [3,4], [5,6]].map {|x, y| x * y}

has output

[2, 12, 30]

as expected but the script

print [[1,2], [3,4], [5,6]].map(:*)

raises an ArgumentError:

confused_ruby_map_inject.rb:1:in `map': wrong number of arguments(1 for 0) (ArgumentError)
    from confused_ruby_map_inject.rb:1:in `<main>'

Why is this happening, what does :* do, and what's the most concise way to achieve the result I'm looking for with the second set of scripts?

Was it helpful?

Solution

inject() can take a block or a symbol, but map() always takes a block. I think your working map() is concise enough.

:* is the symbol name for the multiplication method.

Update: I think your working map() is fine, but it seems like what you might be looking for is the classic map/reduce, even though it's actually longer:

[[1,2], [3,4], [5,6]].map{|a| a.reduce(:*)}

OTHER TIPS

You could do it the following way:

[[1,2], [3,4], [5,6]].collect{|t| t.inject(:*)}

Here you can see how the inject works Enumerable Doc's

Regards,

inject has special syntax; you can get close with map using an ampersand:

print [[1,2], [3,4], [5,6]].map(&:first) #=>[1, 3, 5] #note the ampersand

print [[1,2], [3,4], [5,6]].map(&:*)     #=>in `*': wrong number of arguments(0 for 1) (ArgumentError)

The error is because the *-method takes an argument (either a string or a integer), which is not optional. It is the error you'l get when executing [1,2].*.

Demo of what * does:

p [1,2]*2       #=> [1, 2, 1, 2]
p [1,2]*' and ' #=> "1 and 2"
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top