Best way to convert strings to symbols in hash

前端 未结 30 2969
借酒劲吻你
借酒劲吻你 2020-11-27 09:30

What\'s the (fastest/cleanest/straightforward) way to convert all keys in a hash from strings to symbols in Ruby?

This would be handy when parsing YAML.



        
相关标签:
30条回答
  • 2020-11-27 09:46

    This is for people who uses mruby and do not have any symbolize_keys method defined:

    class Hash
      def symbolize_keys!
        self.keys.each do |k|
          if self[k].is_a? Hash
            self[k].symbolize_keys!
          end
          if k.is_a? String
            raise RuntimeError, "Symbolizing key '#{k}' means overwrite some data (key :#{k} exists)" if self[k.to_sym]
            self[k.to_sym] = self[k]
            self.delete(k)
          end
        end
        return self
      end
    end
    

    The method:

    • symbolizes only keys that are String
    • if symbolize a string means to lose some informations (overwrite part of hash) raise a RuntimeError
    • symbolize also recursively contained hashes
    • return the symbolized hash
    • works in place!
    0 讨论(0)
  • 2020-11-27 09:48

    Since Ruby 2.5.0 you can use Hash#transform_keys or Hash#transform_keys!.

    {'a' => 1, 'b' => 2}.transform_keys(&:to_sym) #=> {:a => 1, :b => 2}
    
    0 讨论(0)
  • 2020-11-27 09:48

    Facets' Hash#deep_rekey is also a good option, especially:

    • if you find use for other sugar from facets in your project,
    • if you prefer code readability over cryptical one-liners.

    Sample:

    require 'facets/hash/deep_rekey'
    my_hash = YAML.load_file('yml').deep_rekey
    
    0 讨论(0)
  • 2020-11-27 09:49

    Would something like the following work?

    new_hash = Hash.new
    my_hash.each { |k, v| new_hash[k.to_sym] = v }
    

    It'll copy the hash, but you won't care about that most of the time. There's probably a way to do it without copying all the data.

    0 讨论(0)
  • 2020-11-27 09:53

    In Ruby >= 2.5 (docs) you can use:

    my_hash.transform_keys(&:to_sym)
    

    Using older Ruby version? Here is a one-liner that will copy the hash into a new one with the keys symbolized:

    my_hash = my_hash.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
    

    With Rails you can use:

    my_hash.symbolize_keys
    my_hash.deep_symbolize_keys 
    
    0 讨论(0)
  • 2020-11-27 09:54

    For the specific case of YAML in Ruby, if the keys begin with ':', they will be automatically interned as symbols.

    require 'yaml'
    require 'pp'
    yaml_str = "
    connections:
      - host: host1.example.com
        port: 10000
      - host: host2.example.com
        port: 20000
    "
    yaml_sym = "
    :connections:
      - :host: host1.example.com
        :port: 10000
      - :host: host2.example.com
        :port: 20000
    "
    pp yaml_str = YAML.load(yaml_str)
    puts yaml_str.keys.first.class
    pp yaml_sym = YAML.load(yaml_sym)
    puts yaml_sym.keys.first.class
    

    Output:

    #  /opt/ruby-1.8.6-p287/bin/ruby ~/test.rb
    {"connections"=>
      [{"port"=>10000, "host"=>"host1.example.com"},
       {"port"=>20000, "host"=>"host2.example.com"}]}
    String
    {:connections=>
      [{:port=>10000, :host=>"host1.example.com"},
       {:port=>20000, :host=>"host2.example.com"}]}
    Symbol
    
    0 讨论(0)
提交回复
热议问题