Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I convert a Ruby hash so that all of its keys are symbols?

Tags:

ruby

hash

I have a Ruby hash which looks like:

{ "id" => "123", "name" => "test" } 

I would like to convert it to:

{ :id => "123", :name => "test" } 
like image 589
ed1t Avatar asked Dec 04 '11 23:12

ed1t


People also ask

How do you change to symbol in Ruby?

Ruby supports both Strings & Symbols. String being mutable & Symbols being immutable cater to different needs. We can convert String to Symbol & Symbol to String at any time. To convert a string to a symbol, we can use intern method or to_sym method which are aliases to each other.

Can a Hash have multiple values Ruby?

Each key can only have one value. But the same value can occur more than once inside a Hash, while each key can occur only once.


2 Answers

hash = {"apple" => "banana", "coconut" => "domino"} Hash[hash.map{ |k, v| [k.to_sym, v] }] #=> {:apple=>"banana", :coconut=>"domino"} 

@mu is too short: Didn't see word "recursive", but if you insist (along with protection against non-existent to_sym, just want to remind that in Ruby 1.8 1.to_sym == nil, so playing with some key types can be misleading):

hash = {"a" => {"b" => "c"}, "d" => "e", Object.new => "g"}  s2s =    lambda do |h|      Hash === h ?        Hash[         h.map do |k, v|            [k.respond_to?(:to_sym) ? k.to_sym : k, s2s[v]]          end        ] : h    end  s2s[hash] #=> {:d=>"e", #<Object:0x100396ee8>=>"g", :a=>{:b=>"c"}} 
like image 85
Victor Moroz Avatar answered Oct 02 '22 11:10

Victor Moroz


If you happen to be in Rails then you'll have symbolize_keys:

Return a new hash with all keys converted to symbols, as long as they respond to to_sym.

and symbolize_keys! which does the same but operates in-place. So, if you're in Rails, you could:

hash.symbolize_keys! 

If you want to recursively symbolize inner hashes then I think you'd have to do it yourself but with something like this:

def symbolize_keys_deep!(h)   h.keys.each do |k|     ks    = k.to_sym     h[ks] = h.delete k     symbolize_keys_deep! h[ks] if h[ks].kind_of? Hash   end end 

You might want to play with the kind_of? Hash to match your specific circumstances; using respond_to? :keys might make more sense. And if you want to allow for keys that don't understand to_sym, then:

def symbolize_keys_deep!(h)   h.keys.each do |k|     ks    = k.respond_to?(:to_sym) ? k.to_sym : k     h[ks] = h.delete k # Preserve order even when k == ks     symbolize_keys_deep! h[ks] if h[ks].kind_of? Hash   end end 

Note that h[ks] = h.delete k doesn't change the content of the Hash when k == ks but it will preserve the order when you're using Ruby 1.9+. You could also use the [(key.to_sym rescue key) || key] approach that Rails uses in their symbolize_keys! but I think that's an abuse of the exception handling system.

The second symbolize_keys_deep! turns this:

{ 'a' => 'b', 'c' => { 'd' => { 'e' => 'f' }, 'g' => 'h' }, ['i'] => 'j' } 

into this:

{ :a => 'b', :c => { :d => { :e => 'f' }, :g => 'h' }, ['i'] => 'j' } 

You could monkey patch either version of symbolize_keys_deep! into Hash if you really wanted to but I generally stay away from monkey patching unless I have very good reasons to do it.

like image 36
mu is too short Avatar answered Oct 02 '22 11:10

mu is too short