Skip to content

Instantly share code, notes, and snippets.

@Integralist
Last active September 2, 2020 08:50
Show Gist options
  • Star 47 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save Integralist/9503099 to your computer and use it in GitHub Desktop.
Save Integralist/9503099 to your computer and use it in GitHub Desktop.
Convert Ruby Hash keys into symbols
hash = { 'foo' => 'bar' }
# Version 1
hash = Hash[hash.map { |k, v| [k.to_sym, v] }]
# Version 2
hash = hash.reduce({}) do |memo, (k, v)|
memo.tap { |m| m[k.to_sym] = v }
end
# Version 3
hash = hash.reduce({}) do |memo, (k, v)|
memo.merge({ k.to_sym => v})
end
# None of the above solutions work with a multi-level hash
# They only work on the first level: {:foo=>"bar", :level1=>{"level2"=>"baz"}}
# The following two variations solve the problem in the same way
multi_hash = { 'foo' => 'bar', 'level1' => { 'level2' => 'baz' } }
# Modify `Object`
class Object
def deep_symbolize_keys
return self.reduce({}) do |memo, (k, v)|
memo.tap { |m| m[k.to_sym] = v.deep_symbolize_keys }
end if self.is_a? Hash
return self.reduce([]) do |memo, v|
memo << v.deep_symbolize_keys; memo
end if self.is_a? Array
self
end
end
multi_hash = multi_hash.deep_symbolize_keys
# Standalone method
def symbolize(obj)
return obj.reduce({}) do |memo, (k, v)|
memo.tap { |m| m[k.to_sym] = symbolize(v) }
end if obj.is_a? Hash
return obj.reduce([]) do |memo, v|
memo << symbolize(v); memo
end if obj.is_a? Array
obj
end
multi_hash = symbolize(multi_hash)
@jlstr
Copy link

jlstr commented Jul 10, 2015

Fantastic!

@samnissen
Copy link

+1

@alambike
Copy link

alambike commented Nov 9, 2015

If I'm not wrong, symbolize function must return obj.to_sym

@chadfennell
Copy link

Thanks. I hadn't known about .tap until seeing this example. Handy. I put together a slightly different version of the standalone method to clarify (for myself) the algorithm.

    def symbolize(obj)
      if obj.is_a? Hash
        return obj.inject({}) do |memo, (k, v)|
          memo.tap { |m| m[k.to_sym] = symbolize(v) }
        end
      elsif obj.is_a? Array
        return obj.map { |memo| symbolize(memo) }
      end
      obj
    end

@JoseAlban
Copy link

Thank you 👍

@henrikj242
Copy link

Sweet, thanks!

@martinezcoder
Copy link

martinezcoder commented Jul 24, 2018

A little trick, using just the Ruby libraries:

hash = { 'foo' => 'bar' }

require 'json'
JSON.parse(hash.to_json, { symbolize_names: true })

With multi hash

multi_hash = { 'foo' => 'bar', 'level1' => { 'level2' => 'baz' } }
=> {"foo"=>"bar", "level1"=>{"level2"=>"baz"}}

JSON.parse(multi_hash.to_json, { symbolize_names: true })
=> {:foo=>"bar", :level1=>{:level2=>"baz"}}

Still easier if you use Rails: https://apidock.com/rails/Hash/symbolize_keys

@rachidcalazans
Copy link

Very nice approach @martinezcoder

@MarioRuiz
Copy link

Cool Gist!
@Integralist I would like to add deep_symbolize_keys method to nice_hash gem: https://github.com/MarioRuiz/nice_hash
Since it is yours.... feel free to add it to the Hash class on https://github.com/MarioRuiz/nice_hash/blob/master/lib/nice/hash/add_to_ruby.rb
Or if you prefer it I can do it and name you in the code.

@yigger
Copy link

yigger commented Feb 20, 2019

awesome!! @martinezcoder

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment