Search code examples
rubyenumerable

what does inject return? and what can be in a block?


In the code below Ocean represents the heights of undersea mountains. atlantis is a set of coordinates for various locations. I want to sum up the heights of the mountains referenced by atlantis.

require 'matrix'    
Ocean=Matrix[ [3,1,4,4,6,2,8,12,8,2],
        [6,2,4,13,25,21,11,22,9,3,],
        [6,20,27,34,22,14,12,11,2,5],
        [6,28,17,23,31,18,11,9,18,12],
        [9,18,11,13,8,9,10,14,24,11],
        [3,9,7,16,9,12,28,24,29,21],
        [5,8,4,7,17,14,19,30,33,4],
        [7,17,23,9,5,9,22,21,12,21,],
        [7,14,25,22,16,10,19,15,12,11],
        [5,16,7,3,6,3,9,8,1,5] ]

atlantis=[[2,3],[3,4]]




puts atlantis.inject {|sum, n| sum + Ocean[n(0),n(1)]}

Since atlantis is an array of arrays, n(0) should refer to the first element, 2, of the first array [2,3] the first time inject does the block. But the error I get

t1.rb:15:in block in <main>': undefined methodn' for main:Object (NoMethodError) from t1.rb:15:in each' from t1.rb:15:ininject' from t1.rb:15:in `'

Seems to indicate it doesn't even know what "n" is. What am I missing? And precisely what does n get/stand for in this case?


Solution

  • From the Ruby documentation for Enumerable#inject(...), that function returns the result of applying the given binary operator repeatedly to the seed and each successive value. So the return value should be an object of the type returned by the block procedure (or symbol). In your case, the block ultimately uses the + operator with numeric arguments, so the returned value should be a Numeric.

    You should modify your attempt by providing a seed value and using the correct syntax for array lookup:

    atlantis.inject(0) { |sum,n| sum + Ocean[n[0],n[1]] } # => 65
    

    So your call sequence will look something like this:

    # sum = seed = 0 (from .inject(0))
    # sum = sum + Ocean[atlantis[0][0], atlantis[0][1]] = 34
    # sum = sum + Ocean[atlantis[1][0], atlantis[1][1]] = 34 + 31
    # sum = 65