a = [[1, 'a'],[2, 'b'],[3, 'c'], [4, 'd']]
a.inject({}) {|r, val| r[val[0]] = val[1]}
When I run this, I get an index error
When I change the block to
a.inject({}) {|r, val| r[val[0]] = val[1]; r}
It then works.
How is ruby handling the first inject attempt that isn’t getting what I want?
Is there a better way to do this?
Just because Ruby is dynamically and implicitly typed doesn’t mean that you don’t have to think about types.
The type of
Enumerable#injectwithout an explicit accumulator (this is usually calledreduce) is something likeor in a more Rubyish notation I just made up
You will notice that all the types are the same. The element type of the
Enumerable, the two argument types of the block, the return type of the block and the return type of the overall method.The type of
Enumerable#injectwith an explicit accumulator (this is usually calledfold) is something likeor
Here you see that the accumulator can have a different type than the element type of the collection.
These two rules generally get you through all
Enumerable#inject-related type problems:In this case, it is Rule #1 that bites you. When you do something like
in your block, assignments evaluate to the assigned value, not the receiver of the assignment. You’ll have to replace this with
See also Why Ruby inject method cannot sum up string lengths without initial value?
BTW: you can use destructuring bind to make your code much more readable: