如何转换Ruby哈希以使其所有键都是符号?

ed1*_*d1t 53 ruby hash

我有一个Ruby哈希,看起来像:

{ "id" => "123", "name" => "test" }
Run Code Online (Sandbox Code Playgroud)

我想将其转换为:

{ :id => "123", :name => "test" }
Run Code Online (Sandbox Code Playgroud)

Vic*_*roz 66

hash = {"apple" => "banana", "coconut" => "domino"}
Hash[hash.map{ |k, v| [k.to_sym, v] }]
#=> {:apple=>"banana", :coconut=>"domino"}
Run Code Online (Sandbox Code Playgroud)

更新:

@mu太短了:没看到"递归"这个词,但是如果你坚持(同时保护不存在to_sym,只想提醒一下,在Ruby 1.8中1.to_sym == nil,所以玩一些关键类型可能会产生误导):

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"}}
Run Code Online (Sandbox Code Playgroud)


mu *_*ort 55

如果您碰巧在Rails中,那么您将拥有symbolize_keys:

返回一个新哈希,所有键都转换为符号,只要它们响应即可to_sym.

symbolize_keys!这不相同,但就地操作.所以,如果你在Rails中,你可以:

hash.symbolize_keys!
Run Code Online (Sandbox Code Playgroud)

如果你想递归地象征内部哈希,那么我认为你必须自己做,但有这样的事情:

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
Run Code Online (Sandbox Code Playgroud)

你可能想玩它kind_of? Hash以符合你的具体情况; 使用respond_to? :keys可能更有意义.如果你想允许不理解的密钥to_sym,那么:

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
Run Code Online (Sandbox Code Playgroud)

请注意,h[ks] = h.delete k这不会改变Hash的内容,k == ks但是当您使用Ruby 1.9+时它将保留顺序.您也可以使用[(key.to_sym rescue key) || key]Rails在其中使用的方法,symbolize_keys!但我认为这是滥用异常处理系统.

第二个symbolize_keys_deep!转向:

{ 'a' => 'b', 'c' => { 'd' => { 'e' => 'f' }, 'g' => 'h' }, ['i'] => 'j' }
Run Code Online (Sandbox Code Playgroud)

进入这个:

{ :a => 'b', :c => { :d => { :e => 'f' }, :g => 'h' }, ['i'] => 'j' }
Run Code Online (Sandbox Code Playgroud)

symbolize_keys_deep!如果你真的想要,你可以修补任何一个版本的哈希,但我通常远离猴子修补,除非我有很好的理由去做.


MRi*_*fat 42

如果您使用Rails> = 4,您可以使用:

hash.deep_symbolize_keys
hash.deep_symbolize_keys!
Run Code Online (Sandbox Code Playgroud)

要么

hash.deep_stringify_keys
hash.deep_stringify_keys!
Run Code Online (Sandbox Code Playgroud)

请参阅http://apidock.com/rails/v4.2.1/Hash/deep_symbolize_keys


Ale*_*pov 18

为了防止您解析JSON,您可以在json docs中添加选项,以便在解析时对符号进行符号化:

hash = JSON.parse(json_data, symbolize_names: true)
Run Code Online (Sandbox Code Playgroud)

  • 我实际上做了很多:`hash = JSON.parse(hash.to_json,symbolize_names:true)`. (4认同)

pje*_*pje 11

Victor Moroz为简单的递归案例提供了一个可爱的答案,但它不会处理嵌套在嵌套数组中的哈希:

hash = { "a" => [{ "b" => "c" }] }
s2s[hash] #=> {:a=>[{"b"=>"c"}]}
Run Code Online (Sandbox Code Playgroud)

如果你需要在哈希中支持数组中的哈希,你会想要更像这样的东西:

def recursive_symbolize_keys(h)
  case h
  when Hash
    Hash[
      h.map do |k, v|
        [ k.respond_to?(:to_sym) ? k.to_sym : k, recursive_symbolize_keys(v) ]
      end
    ]
  when Enumerable
    h.map { |v| recursive_symbolize_keys(v) }
  else
    h
  end
end
Run Code Online (Sandbox Code Playgroud)


bon*_*dog 7

如果您使用 Rails(或仅使用 Active Support):

{ "id" => "123", "name" => "test" }.symbolize_keys
Run Code Online (Sandbox Code Playgroud)

  • 或者递归版本,[deep_symbolize_keys](http://api.rubyonrails.org/classes/Hash.html#method-i-deep_symbolize_keys) (4认同)

Cha*_*tos 6

这是一个比所选答案更快的 Ruby 单行代码:

hash = {"apple" => "banana", "coconut" => "domino"}
#=> {"apple"=>"banana", "coconut"=>"domino"}

hash.inject({}){|h,(k,v)| h[k.intern] = v; h}
#=> {:apple=>"banana", :coconut=>"domino"}
Run Code Online (Sandbox Code Playgroud)

基准测试结果:

n = 100000

Benchmark.bm do |bm|
  bm.report { n.times { hash.inject({}){|h,(k,v)| h[k.intern] = v; h} } }
  bm.report { n.times { Hash[hash.map{ |k, v| [k.to_sym, v] }] } }
end

# =>       user     system      total        real
# =>   0.100000   0.000000   0.100000 (  0.107940)
# =>   0.120000   0.010000   0.130000 (  0.137966)
Run Code Online (Sandbox Code Playgroud)


Pau*_*lgo 6

从 Ruby 2.5 开始,您可以使用该transform_key方法。

所以在你的情况下,它将是:

h = { "id" => "123", "name" => "test" }
h.transform_keys!(&:to_sym)      #=> {:id=>"123", :name=>"test"}
Run Code Online (Sandbox Code Playgroud)

注意:同样的方法也可以在 Ruby on Rails 上使用。

  • 请注意,这不会递归为嵌套哈希 (2认同)

Joh*_*lla 5

试试这个:

hash = {"apple" => "banana", "coconut" => "domino"}
 # => {"apple"=>"banana", "coconut"=>"domino"} 

hash.tap do |h|
  h.keys.each { |k| h[k.to_sym] = h.delete(k) }
end
 # => {:apple=>"banana", :coconut=>"domino"} 
Run Code Online (Sandbox Code Playgroud)

这会遍历密钥,对于每个密钥,它会删除字符串化密钥并将其值分配给符号化密钥.