将string转换为散列符号的最佳方法

什么(最快/最干净/直接)的方式来将所有的哈希密钥从string转换为Ruby中的符号?

这在parsingYAML时会很方便。

my_hash = YAML.load_file('yml') 

我想能够使用:

 my_hash[:key] 

而不是:

 my_hash['key'] 

如果你想要一个class轮,

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

将密钥复制到一个新的密钥符号。

这里有一个更好的方法,如果你使用的是Rails:

PARAMS。 symbolize_keys

结束。

如果你不是,只需撕掉他们的代码(它也在链接中):

 myhash.keys.each do |key| myhash[(key.to_sym rescue key) || key] = myhash.delete(key) end 

对于Ruby中YAML的具体情况,如果键以' : '开始,它们将被自动作为符号来实现。

要求'yaml'
要求'pp'
 yaml_str =“
连接:
   - 主机:host1.example.com
    端口:10000
   -  host:host2.example.com
    端口:20000
 “
 yaml_sym =“
 :连接:
   - :host:host1.example.com
     :端口:10000
   - :host:host2.example.com
     :端口:20000
 “
 pp yaml_str = YAML.load(yaml_str)
放入yaml_str.keys.first.class
 pp yaml_sym = YAML.load(yaml_sym)
放入yaml_sym.keys.first.class

输出:

 #/opt/ruby-1.8.6-p287/bin/ruby〜/ test.rb
 { “连接”=>
   [{“port”=> 10000,“host”=>“host1.example.com”},
    {“port”=> 20000,“host”=>“host2.example.com”}]}
串
 {:连接=>
   [{:port => 10000,:host =>“host1.example.com”},
    {:port => 20000,:host =>“host2.example.com”}]}
符号

更简洁:

 Hash[my_hash.map{|(k,v)| [k.to_sym,v]}] 

如果您使用的是Rails,那就更简单了 – 您可以使用HashWithIndifferentAccess并以string和符号的forms访问这些键:

 my_hash.with_indifferent_access 

也可以看看:

http://api.rubyonrails.org/classes/ActiveSupport/HashWithIndifferentAccess.html


或者,您可以使用真棒“Ruby的小平面”gem,其中包含了很多的Ruby Core和标准库类的扩展。

  require 'facets' > {'some' => 'thing', 'foo' => 'bar'}.symbolize_keys => {:some=>"thing", :foo=>"bar} 

另请参阅: http : //rubyworks.github.io/rubyfaux/?doc=http : //rubyworks.github.io/facets/docs/facets-2.9.3/core.json#api-class-Hash

http://api.rubyonrails.org/classes/Hash.html#method-i-symbolize_keys

 hash = { 'name' => 'Rob', 'age' => '28' } hash.symbolize_keys # => { name: "Rob", age: "28" } 

这是深度象征对象的一种方法

 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 

我真的很喜欢Mashgem。

你可以做mash['key']或者mash[:key]或者mash.key

params.symbolize_keys也将工作。 此方法将散列键变成符号并返回一个新的散列。

对@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 

这是我的一个嵌套散列的class轮

 def symbolize_keys(hash) hash.each_with_object({}) { |(k, v), h| h[k.to_sym] = v.is_a?(Hash) ? symbolize_keys(v) : v } end 

这里有很多答案,但是一个方法rails函数是hash.symbolize_keys

你可能很懒,用一个lambda包装:

 my_hash = YAML.load_file('yml') my_lamb = lambda { |key| my_hash[key.to_s] } my_lamb[:a] == my_hash['a'] #=> true 

但是这只能用于从散列阅读 – 不写。

要做到这一点,你可以使用Hash#merge

 my_hash = Hash.new { |h,k| h[k] = h[k.to_s] }.merge(YAML.load_file('yml')) 

init块会根据需要一次转换键,但如果在访问符号版本后更新键的string版本值,符号版本将不会更新。

 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} 

你也可以让init块不更新散列,这样可以保护你免受这种错误的影响,但是你仍然容易受到相反的影响 – 更新符号版本不会更新string版本:

 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} 

所以要小心的是在两个关键forms之间切换。 坚持一个。

一个更短的单线程:

 my_hash.inject({}){|h,(k,v)| h.merge({ k.to_sym => v}) } 

会像下面的工作?

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

它会复制散列,但大部分时间你都不会在意。 可能有办法做到这一点,而不复制所有的数据。

这个怎么样:

 my_hash = HashWithIndifferentAccess.new(YAML.load_file('yml')) # my_hash['key'] => "val" # my_hash[:key] => "val" 

我们想要改变的数组。

string= [“HTML”,“CSS”,“JavaScript”,“Python”,“Ruby”]

把一个新的variables作为一个空的数组,这样我们就可以“

符号= []

这里是我们用块定义一个方法的地方。

strings.each {| x | symbols.push(x.intern)}

代码结束。

所以这可能是在Ruby中将string转换为数组中符号的最直接的方法。 创build一个string数组,然后创build一个新variables并将该variables设置为一个空数组。 然后select您使用“.each”方法创build的第一个数组中的每个元素。 然后使用块代码来“压缩”新数组中的所有元素,并使用“.intern或.to_sym”将所有元素转换为符号。

符号速度更快,因为它们可以在代码中保存更多的内存,并且只能使用一次。 符号是最常用的密钥散列这是伟大的。 我不是最好的ruby程序员,但这种代码forms帮了我很多。如果有人知道更好的方式,请分享,你也可以使用这种方法散列!

如果你想香草ruby解决scheme,因为我没有访问ActiveSupport这里是深刻的符号化解决scheme(非常类似于以前的)

  def deep_convert(element) return element.collect { |e| deep_convert(e) } if element.is_a?(Array) return element.inject({}) { |sh,(k,v)| sh[k.to_sym] = deep_convert(v); sh } if element.is_a?(Hash) element end 

如果您需要这样做的原因是因为您的数据最初来自JSON,那么您可以在接收JSON时通过传入:symbolize_names选项来跳过任何parsing。

没有Rails的要求,并与Ruby> 1.9

 JSON.parse(my_json, :symbolize_names => true) 

这是为那些使用mruby并且没有定义任何symbolize_keys方法的人使用的:

 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 

方法:

  • 象征只有String
  • 如果象征一个string意味着丢失一些信息(覆盖散列的一部分)引发一个RuntimeError
  • 也象征recursion地包含了散列
  • 返回符号化的散列
  • 工作到位!
 ruby-1.9.2-p180 :001 > h = {'aaa' => 1, 'bbb' => 2} => {"aaa"=>1, "bbb"=>2} ruby-1.9.2-p180 :002 > Hash[h.map{|a| [a.first.to_sym, a.last]}] => {:aaa=>1, :bbb=>2} 

这并不完全是一蹴而就的,但它将所有string键转换为符号,也是嵌套的:

 def recursive_symbolize_keys(my_hash) case my_hash when Hash Hash[ my_hash.map do |key, value| [ key.respond_to?(:to_sym) ? key.to_sym : key, recursive_symbolize_keys(value) ] end ] when Enumerable my_hash.map { |value| recursive_symbolize_keys(value) } else my_hash end end 

当我不使用Rails的时候,我喜欢这个一行代码,因为那样我就不必再做第二个散列,并且在处理它的时候保存两组数据:

 my_hash = { "a" => 1, "b" => "string", "c" => true } my_hash.keys.each { |key| my_hash[key.to_sym] = my_hash.delete(key) } my_hash => {:a=>1, :b=>"string", :c=>true} 

哈希#删除返回已删除键的值

Facets的Hash#deep_rekey也是一个不错的select,特别是:

  • 如果您在项目中使用其他方面的糖,
  • 如果你喜欢密码单行的代码可读性。

样品:

 require 'facets/hash/deep_rekey' my_hash = YAML.load_file('yml').deep_rekey 

在ruby中,我发现这是最简单,最容易理解的方法,将哈希中的string键转换为符号:

 my_hash.keys.each { |key| my_hash[key.to_sym] = my_hash.delete(key)} 

对于散列中的每个关键字,我们都会调用delete来将其从hash中删除(delete也会返回与被删除的关键字相关的值 ),我们立即将其设置为符号化的关键字。

 {'g'=> 'a', 2 => {'v' => 'b', 'x' => { 'z' => 'c'}}}.deep_symbolize_keys! 

转换为:

 {:g=>"a", 2=>{:v=>"b", :x=>{:z=>"c"}}} 

recursion地为任何哈希symbolics_keys:

 class Hash def symbolize_keys self.is_a?(Hash) ? Hash[ self.map { |k,v| [k.respond_to?(:to_sym) ? k.to_sym : k, v.is_a?(Hash) ? v.symbolize_keys : v] } ] : self end end