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 b
The first block returns the result of the assignment back into the inject, the second returns the hash, so it actually works.
A lot of people consider this usage of inject an anti-pattern; consider each_with_object instead.
Just because Ruby is dynamically and implicitly typed doesn't mean that you don't have to think about types.
The type of Enumerable#inject without an explicit accumulator (this is usually called reduce) is something like
reduce :: [a] → (a → a → a) → a
or in a more Rubyish notation I just made up
Enumerable[A]#inject {|A, A| A } → A
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#inject with an explicit accumulator (this is usually called fold) is something like
fold :: [b] → a → (a → b → a) → a
or
Enumerable[B]#inject(A) {|A, B| A } → A
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
acc[key] = value
in your block, assignments evaluate to the assigned value, not the receiver of the assignment. You'll have to replace this with
acc.tap { acc[key] = value }
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:
a.inject({}) {|r, (key, value)| r[key] = value; r }
a.inject({}) { |r, val| r.merge({ val[0] => val[1] }) }
There is an easier way -
a = [[1, 'a'],[2, 'b'],[3, 'c'], [4, 'd']]
b = Hash[a] # {1=>"a", 2=>"b", 3=>"c", 4=>"d"}
The reason the first method isn't working, is because inject uses the result of the block as the r in the next iteration. For the first iteration, r is set to the argument you pass to it, which in this case is {}.