Ruby inject with initial being a hash

Ruby

Ruby Problem Overview


Can any one tell me why the following:

['a', 'b'].inject({}) {|m,e| m[e] = e }

throws the error:

IndexError: string not matched
        from (irb):11:in `[]='
        from (irb):11:in `block in irb_binding'
        from (irb):11:in `each'
        from (irb):11:in `inject'
        from (irb):11
        from C:/Ruby192/bin/irb:12:in `<main>'

whereas the following works?

a = {}
a["str"] = "str"

Ruby Solutions


Solution 1 - Ruby

Your block needs to return the accumulating hash:

['a', 'b'].inject({}) {|m,e| m[e] = e; m }

Instead, it's returning the string 'a' after the first pass, which becomes m in the next pass and you end up calling the string's []= method.

Solution 2 - Ruby

The block must return the accumulator (the hash), as @Rob said. Some alternatives:

With Hash#update:

hash = ['a', 'b'].inject({}) { |m, e| m.update(e => e) }

With Enumerable#each_with_object:

hash = ['a', 'b'].each_with_object({}) { |e, m| m[e] = e }

With Hash#[]:

hash = Hash[['a', 'b'].map { |e| [e, e] }]

With Array#to_h (Ruby >= 2.1):

hash = ['a', 'b'].map { |e| [e, e] }.to_h

With Enumerable#mash from Facets:

require 'facets'
hash = ['a', 'b'].mash { |e| [e, e] }

Solution 3 - Ruby

Rather than using inject, you should look into [Enumerable#each_with_object][1].

Where inject requires you to return the object being accumulated into, each_with_object does it automatically.

From the docs:

>Iterates the given block for each element with an arbitrary object given, and returns the initially given object. > >If no block is given, returns an enumerator. > >e.g.:

evens = (1..10).each_with_object([]) {|i, a| a << i*2 }
#=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

So, closer to your question:

[1] pry(main)> %w[a b].each_with_object({}) { |e,m| m[e] = e }
=> {"a"=>"a", "b"=>"b"}

Notice that inject and each_with_object reverse the order of the yielded parameters. [1]: http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-each_with_object

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCandideView Question on Stackoverflow
Solution 1 - RubyRob DavisView Answer on Stackoverflow
Solution 2 - RubytoklandView Answer on Stackoverflow
Solution 3 - Rubythe Tin ManView Answer on Stackoverflow