如何转换 Ruby 散列,使其所有键都是符号?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8379596/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I convert a Ruby hash so that all of its keys are symbols?
提问by ed1t
I have a Ruby hash which looks like:
我有一个 Ruby 哈希,它看起来像:
{ "id" => "123", "name" => "test" }
I would like to convert it to:
我想将其转换为:
{ :id => "123", :name => "test" }
回答by Victor Moroz
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):
@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"}}
回答by mu is too short
If you happen to be in Rails then you'll have symbolize_keys:
如果您碰巧在 Rails 中,那么您将拥有symbolize_keys:
Return a new hash with all keys converted to symbols, as long as they respond to
to_sym.
返回一个新的散列,其中所有键都转换为符号,只要它们响应
to_sym.
and symbolize_keys!which does the same but operates in-place. So, if you're in Rails, you could:
并symbolize_keys!执行相同的操作,但就地操作。所以,如果你在 Rails 中,你可以:
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? Hashto match your specific circumstances; using respond_to? :keysmight make more sense. And if you want to allow for keys that don't understand to_sym, then:
您可能想根据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
Note that h[ks] = h.delete kdoesn't change the content of the Hash when k == ksbut 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.
请注意,当您使用 Ruby 1.9+ 时,h[ks] = h.delete k它不会更改 Hash 的内容,k == ks但会保留顺序。您也可以使用[(key.to_sym rescue key) || key]Rails 在他们的方法中使用的方法,symbolize_keys!但我认为这是对异常处理系统的滥用。
The second symbolize_keys_deep!turns this:
第二个symbolize_keys_deep!变成了这个:
{ '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.
symbolize_keys_deep!如果你真的想的话,你可以将任何一个版本的猴子修补到 Hash 中,但我通常远离猴子修补,除非我有很好的理由这样做。
回答by MRifat
If you are using Rails >= 4 you can use:
如果您使用 Rails >= 4,您可以使用:
hash.deep_symbolize_keys
hash.deep_symbolize_keys!
or
或者
hash.deep_stringify_keys
hash.deep_stringify_keys!
see http://apidock.com/rails/v4.2.1/Hash/deep_symbolize_keys
回答by Alexander
回答by pje
Victor Morozprovided a lovely answer for the simple recursive case, but it won't process hashes that are nested within nested arrays:
Victor Moroz为简单的递归情况提供了一个可爱的答案,但它不会处理嵌套在嵌套数组中的哈希:
hash = { "a" => [{ "b" => "c" }] }
s2s[hash] #=> {:a=>[{"b"=>"c"}]}
If you need to support hashes within arrays within hashes, you'll want something more like this:
如果您需要在散列中的数组内支持散列,您将需要更像这样的东西:
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
回答by John Feminella
Try this:
尝试这个:
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"}
This iterates over the keys, and for each one, it deletes the stringified key and assigns its value to the symbolized key.
这将迭代键,对于每个键,它删除字符串化键并将其值分配给符号化键。
回答by bonkydog
If you're using Rails (or just Active Support):
如果您使用 Rails(或仅使用 Active Support):
{ "id" => "123", "name" => "test" }.symbolize_keys
回答by Paulo Fidalgo
Starting with Ruby 2.5 you can use the transform_keymethod.
从 Ruby 2.5 开始,您可以使用该transform_key方法。
So in your case it would be:
所以在你的情况下,它将是:
h = { "id" => "123", "name" => "test" }
h.transform_keys!(&:to_sym) #=> {:id=>"123", :name=>"test"}
Note: the same methods are also available on Ruby on Rails.
注意:同样的方法也可以在 Ruby on Rails 上使用。
回答by Chakaitos
Here's a Ruby one-liner that is faster than the chosen answer:
这是一个比所选答案更快的 Ruby 单线:
hash = {"apple" => "banana", "coconut" => "domino"}
#=> {"apple"=>"banana", "coconut"=>"domino"}
hash.inject({}){|h,(k,v)| h[k.intern] = v; h}
#=> {:apple=>"banana", :coconut=>"domino"}
Benchmark results:
基准测试结果:
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)
回答by David Fabreguette
You can also extend core Hash ruby class placing a /lib/hash.rb file :
您还可以扩展核心 Hash ruby 类,放置一个 /lib/hash.rb 文件:
class Hash
def symbolize_keys_deep!
new_hash = {}
keys.each do |k|
ks = k.respond_to?(:to_sym) ? k.to_sym : k
if values_at(k).first.kind_of? Hash or values_at(k).first.kind_of? Array
new_hash[ks] = values_at(k).first.send(:symbolize_keys_deep!)
else
new_hash[ks] = values_at(k).first
end
end
new_hash
end
end
If you want to make sure keys of any hash wrapped into arrays inside your parent hash are symbolized, you need to extend also array class creating a "array.rb" file with that code :
如果您想确保包装到父哈希中的数组中的任何哈希的键都被符号化,您还需要扩展数组类,使用该代码创建一个“array.rb”文件:
class Array
def symbolize_keys_deep!
new_ar = []
self.each do |value|
new_value = value
if value.is_a? Hash or value.is_a? Array
new_value = value.symbolize_keys_deep!
end
new_ar << new_value
end
new_ar
end
end
This allows to call "symbolize_keys_deep!" on any hash variable like this :
这允许调用“symbolize_keys_deep!” 在任何这样的哈希变量上:
myhash.symbolize_keys_deep!

