0

I have this code

notebooks.inject([]) do |res, nb|
  res << nb.guid if Recipe::NOTEBOOKS.include?(nb.name)
end

The first nb has matches the condition and res looks like this

["xxx1234"]

The second nb does not match the condition which then delete/clears res

nil

From my understanding, the first value should remain in the array.

I'm also assigning this to a variable and want it to be a one liner.

3 Answers 3

4

inject works a little differently from how you're imagining. It simply returns the last return value of the loop as it loops through each item. An easy way to fix this is:

notebooks.inject([]) do |res, nb|
  res << nb.guid if Recipe::NOTEBOOKS.include?(nb.name)
  res # Returns the res array
end

That said, you should probably use select for your use case as you seem to be just filtering down which set of notebooks you want.. That is:

notebooks.select{|nb| Recipe::NOTEBOOKS.include?(nb.name)}.map(&:guid)

Generally, I've used inject when I need to run math on a group of items. e.g.

[1,2,3,4].inject(0) {|res, x| x * 2 + res}
Sign up to request clarification or add additional context in comments.

Comments

1

If you're open to two loops, but cleaner and still one-liner:

notebooks.select { |nb| Recipe::NOTEBOOKS.include?(nb.name) }.map(&:guid)

1 Comment

+1 Exactly what I was thinking. This helps readability too, because you're splitting the problem into 2 distinct steps. I'd break it into at least 2 lines though.
0

The accumulator must be returned on each loop iteration:

notebooks.inject([]) do |res, nb|
  Recipe::NOTEBOOKS.include?(nb.name) ? res << nb.guid : res
end

Actually, on each subsequent loop iteration, the accumulator passed to res block parameter is exactly what was returned from the previous iteration.

In your example, on the second iteration if returns false and

res << nb.guid if Recipe::NOTEBOOKS.include?(nb.name)

line is not executed at all. That said, after the second iteration, the accumulator takes a brand new value, that is apparently nil.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.