My_inject specs

I’ve been working on the my_inject method in the 03_iteration exercise (as the extension of the my_each method earlier), and I’ve run into a frustrating issue that I haven’t been able to find a resolution to.

My code:

def my_inject(acc = nil, &blk)
  my_each do |el|
    if acc.nil? 
      acc = el
    else
      acc = blk.call(acc, el)
    end
  end
  
  acc
end

There are five specs that we need to pass:

#my_inject

  • calls the block passed to it
  • makes the first element the accumulator if no default is given (FAILED - 1)
  • yields the accumulator and each element to the block (FAILED - 2)
  • does NOT call the built-in #inject method
  • is chainable and returns a new array

I am unsure why my definition of my_inject doesn’t pass the second and third spec. I’m assuming the error is related because when I run bundle exec rspec 03_iteration_spec.rb, it gives me the same error for both these specs:

 Failure/Error: expect do |block|
   expected given block to yield successively with arguments, but yielded with unexpected arguments
   expected: [["el1", "el2"], [nil, "el3"]]
        got: [["el1", "el2"]]

Could someone explain to me what exactly the yield_successive_args in the spec is expecting here?

Before your conditional, inside your my_each block, try putsing/printing your acc and el. See if they’re what you expect them to be.

Thanks for the reply, Michael.

I had the following lines at the top of the my_each block:

puts "acc: " + acc.to_s
puts "el: " + el.to_s

I called a simple summation inject with:

puts [1,2,3,4,5].my_inject { |acc, el| acc + el }

and it outputted exactly what I was expecting:

acc:
el: 1
acc: 1
el: 2
acc: 3
el: 3
acc: 6
el: 4
acc: 10
el: 5
15

so I’m still unsure why exactly the specs are failing. Could you explain to me the significance of what the spec “expects” in this case? Particularly why with an array of [el1, el2, el3], it expects [[el1, el2], [nil, el3]]?

Ahhhh I see what’s happening here. If you drop a console.log inside of your:

if acc.nil?

You’ll see that you hit that at each iteration after the first blk.call. That’s because our spec returns nil when the block is called. Just keep your acc.nil? check out of the my_each, make sure you skip the first item in the array if so, and you should be fine.

Also, do you have to use my_each here?

Oh, I see! So I’ve changed a few things, and it works now:

  • I’ve set acc = self[0] instead of acc = nil as the default argument, as I thought it would make the logic of the code easier to read
  • I created a skip_one boolean so that I can skip the first element of the array in my_each (otherwise it double-counts that first element) instead of the if acc.nil? that I had earlier. Is there a nicer way to manage that? The instructions in the file say to use the my_each method that we coded earlier in the exercise, so I was trying to avoid using other enumerables (specifically, with_index).
1 Like

That sounds totally fine. You would normally do this without an each loop (it’s easier to keep track of indices instead), but you want to be able to think of all the possible ways to can solve a problem. Great job!