I have a Ruby hash which looks like:
{ "id" => "123", "name" => "test" }
I would like to convert it to:
{ :id => "123", :name => "test" }
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.
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.
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"}}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With