什么是(最快/最干净/直接)的方式将哈希中的所有键从字符串转换为符号?
解析YAML时这很方便.
my_hash = YAML.load_file('yml')
Run Code Online (Sandbox Code Playgroud)
我希望能够使用:
my_hash[:key]
Run Code Online (Sandbox Code Playgroud)
而不是:
my_hash['key']
Run Code Online (Sandbox Code Playgroud)
Sai*_*Sai 304
如果你使用Rails,这是一个更好的方法:
PARAMS.symbolize_keys
结束.
如果你不是,只需删掉他们的代码(它也在链接中):
myhash.keys.each do |key|
myhash[(key.to_sym rescue key) || key] = myhash.delete(key)
end
Run Code Online (Sandbox Code Playgroud)
Sar*_*Mei 220
如果你想要一个单线,
my_hash = my_hash.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
Run Code Online (Sandbox Code Playgroud)
将符号化的键复制到新的哈希值.
小智 112
对于Ruby中YAML的特定情况,如果键以' :' 开头,它们将自动作为符号实现.
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
输出:
# /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
Mic*_*ton 61
更简洁:
Hash[my_hash.map{|(k,v)| [k.to_sym,v]}]
Run Code Online (Sandbox Code Playgroud)
Til*_*ilo 57
如果您正在使用Rails,它会更简单 - 您可以使用HashWithIndifferentAccess并以String和Symbols的形式访问键:
my_hash.with_indifferent_access
Run Code Online (Sandbox Code Playgroud)
也可以看看:
http://api.rubyonrails.org/classes/ActiveSupport/HashWithIndifferentAccess.html
或者你可以使用令人敬畏的"Ruby的Facets"Gem,它包含许多Ruby Core和Standard Library类的扩展.
require 'facets'
> {'some' => 'thing', 'foo' => 'bar'}.symbolize_keys
=> {:some=>"thing", :foo=>"bar}
Run Code Online (Sandbox Code Playgroud)
另见:http: //rubyworks.github.io/rubyfaux/?doc = http://rubyworks.github.io/facets/docs/facets-2.9.3/core.json#api-class-Hash
Sag*_*dya 48
既然Ruby 2.5.0你可以使用Hash#transform_keys或Hash#transform_keys!.
{'a' => 1, 'b' => 2}.transform_keys(&:to_sym) #=> {:a => 1, :b => 2}
Run Code Online (Sandbox Code Playgroud)
小智 31
http://api.rubyonrails.org/classes/Hash.html#method-i-symbolize_keys
hash = { 'name' => 'Rob', 'age' => '28' }
hash.symbolize_keys
# => { name: "Rob", age: "28" }
Run Code Online (Sandbox Code Playgroud)
小智 26
这是一种深度符号化对象的方法
def symbolize(obj)
return obj.inject({}){|memo,(k,v)| memo[k.to_sym] = symbolize(v); memo} if obj.is_a? Hash
return obj.inject([]){|memo,v | memo << symbolize(v); memo} if obj.is_a? Array
return obj
end
Run Code Online (Sandbox Code Playgroud)
Mar*_*ark 15
如果您正在使用json,并希望将其用作哈希,那么在核心Ruby中您可以这样做:
json_obj = JSON.parse(json_str, symbolize_names: true)
Run Code Online (Sandbox Code Playgroud)
symbolize_names:如果设置为true,则返回JSON对象中名称(键)的符号.否则返回字符串.字符串是默认值.
Doc:Json #parse symbolize_names
Ton*_*ony 10
@igorsales答案的修改
class Object
def deep_symbolize_keys
return self.inject({}){|memo,(k,v)| memo[k.to_sym] = v.deep_symbolize_keys; memo} if self.is_a? Hash
return self.inject([]){|memo,v | memo << v.deep_symbolize_keys; memo} if self.is_a? Array
return self
end
end
Run Code Online (Sandbox Code Playgroud)
{'g'=> 'a', 2 => {'v' => 'b', 'x' => { 'z' => 'c'}}}.deep_symbolize_keys!
Run Code Online (Sandbox Code Playgroud)
转换为:
{:g=>"a", 2=>{:v=>"b", :x=>{:z=>"c"}}}
Run Code Online (Sandbox Code Playgroud)
小智 7
这是我用于嵌套哈希的一个衬垫
def symbolize_keys(hash)
hash.each_with_object({}) { |(k, v), h| h[k.to_sym] = v.is_a?(Hash) ? symbolize_keys(v) : v }
end
Run Code Online (Sandbox Code Playgroud)
你可以偷懒,把它包装在一个lambda:
my_hash = YAML.load_file('yml')
my_lamb = lambda { |key| my_hash[key.to_s] }
my_lamb[:a] == my_hash['a'] #=> true
Run Code Online (Sandbox Code Playgroud)
但这仅适用于从哈希读取 - 而不是写入。
为此,您可以使用 Hash#merge
my_hash = Hash.new { |h,k| h[k] = h[k.to_s] }.merge(YAML.load_file('yml'))
Run Code Online (Sandbox Code Playgroud)
init 块将按需转换密钥一次,但如果您在访问符号版本后更新密钥的字符串版本的值,符号版本将不会更新。
irb> x = { 'a' => 1, 'b' => 2 }
#=> {"a"=>1, "b"=>2}
irb> y = Hash.new { |h,k| h[k] = h[k.to_s] }.merge(x)
#=> {"a"=>1, "b"=>2}
irb> y[:a] # the key :a doesn't exist for y, so the init block is called
#=> 1
irb> y
#=> {"a"=>1, :a=>1, "b"=>2}
irb> y[:a] # the key :a now exists for y, so the init block is isn't called
#=> 1
irb> y['a'] = 3
#=> 3
irb> y
#=> {"a"=>3, :a=>1, "b"=>2}
Run Code Online (Sandbox Code Playgroud)
您也可以让 init 块不更新哈希,这可以保护您免受这种错误的影响,但您仍然容易受到相反的影响 - 更新符号版本不会更新字符串版本:
irb> q = { 'c' => 4, 'd' => 5 }
#=> {"c"=>4, "d"=>5}
irb> r = Hash.new { |h,k| h[k.to_s] }.merge(q)
#=> {"c"=>4, "d"=>5}
irb> r[:c] # init block is called
#=> 4
irb> r
#=> {"c"=>4, "d"=>5}
irb> r[:c] # init block is called again, since this key still isn't in r
#=> 4
irb> r[:c] = 7
#=> 7
irb> r
#=> {:c=>7, "c"=>4, "d"=>5}
Run Code Online (Sandbox Code Playgroud)
所以要注意这些是在两个关键形式之间切换。坚持一个。
万一您需要执行此操作的原因是因为您的数据最初来自JSON,则可以通过在:symbolize_names导入JSON时仅传递选项来跳过任何解析。
不需要Rails,并且可以与Ruby> 1.9一起使用
JSON.parse(my_json, :symbolize_names => true)
Run Code Online (Sandbox Code Playgroud)