inicio mail me! sindicaci;ón

Ruby: map Array to Hash

Sometimes you may wish to map an Array to a Hash in Ruby, like say, you got the output of I18n.available_locales

locales = [:en, :de, :fr]

and want to transform that into a Hash to fill a select element, like so:

{:en => 'EN', :de => 'DE', :fr => 'FR'}

How do you do that in the most concise way?
First, there is always inject:

locales.inject({}) {|hsh, sym| hsh[sym] = sym.to_s.upcase; hsh}

But I like the following approach way better, mainly because it emphasizes my intention more clearly (and, btw. is faster too):

Hash[locales.map{|sym| [sym, sym.to_s.upcase]}]

Remember: Hash[[[:a,:b],[:c,:d]]] (as well as Hash[:a,:b,:c,:d])
produces {:a => :b, :c => :d}.

Rudy Rigot said,

Januar 27, 2014 @ 10:09 pm

Even though it is true that Hash[:a,:b,:c,:d] produces {:a => :b, :c => :d}, I believe the Hash initialization that is happening here is more the one where Hash[ [[:a,:b],[:c,:d]] ] produces {:a => :b, :c => :d}.

Both are correct (http://www.ruby-doc.org/core-2.1.0/Hash.html#method-c-5B-5D), but here, the result of locales.map is a single array that contains two-element arrays (the ones returned in map’s block), which is why it works.

Thanks though, I was looking for information about that, and this post helped me greatly to understand the best practice.

aljoscha said,

Januar 27, 2014 @ 10:53 pm

You are absolutely right, corrected.

Jechol Lee said,

Juni 1, 2015 @ 2:08 pm

Hash[[:a,:b],[:c,:d]] produces {[:a, :b]=>[:c, :d]}

You need more brackets [], so

Hash[[[:a, :b], [:c, :d]]]

is correct.

aljoscha said,

Juni 1, 2015 @ 2:45 pm

@Jechol: True, corrected, thanks! Stupid me.

Rich said,

Februar 8, 2016 @ 2:32 pm

I found it hard to believe there wasn’t a gem for this already, so I created one: https://rubygems.org/gems/map_h

Using map_h, your original example could be written:

require ‘map_h’
locales.map_h {|sym| sym.to_s.upcase}

RSS feed for comments on this post · TrackBack URI

Schreibe einen Kommentar