2009-04-28 99 views
200

将哈希中所有键从字符串转换为Ruby中符号的(最快/最简洁/直接)方法是什么?将字符串转换为哈希中符号的最佳方法

这在解析YAML时会很方便。

my_hash = YAML.load_file('yml') 

我希望能够使用:

my_hash[:key] 

不是:

my_hash['key'] 
+0

[dup](http://stackoverflow.com/q/8379596/119790)? – 2012-05-11 14:38:44

+59

如果您使用的是Rails,则使用`hash.symbolize_keys`和`hash.deep_symbolize_keys`来完成这项工作。 – Zaz 2014-08-06 17:17:34

+0

Josh如果你会把你的评论放入一个答案,我会投票给你。需要'rails'; hash.deep_symbolize_keys在irb或pry中工作得很好。 :D – 2015-02-07 10:17:36

回答

185

如果你想要一个班轮,

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

将哈希复制到一个新的钥匙象征。

+0

看起来它应该对我有用,但是: my_hash = {'foo'=>'bar','fiz'=>'buzz'} my_hash.inject({}){| memo,( K,v)|备忘录[k.to_sym] = v;备忘录} my_hash [:foo]#=>无 my_hash ['foo']#=>“bar” 现在已经很晚了,我很累。我的大脑可能会遗漏部分难题,或者使用inject()的更精细的点。 – 2009-04-29 02:55:25

+5

啊,抱歉不清楚 - 注入不会修改调用者。你需要做my_hash = my_hash.inject({}){| memo,(k,v)|备忘录[k.to_sym] = v;备忘录} – 2009-04-29 19:06:10

+3

这正是我所期待的。我修改了一下,并添加了一些行,甚至可以在嵌套散列中创建符号。看看这里,如果你有兴趣:http://www.any-where.de/blog/ruby-hash-convert-string-keys-to-symbols/ – Matt 2009-08-19 14:57:56

2

会像下面这样的工作?

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

它会复制哈希值,但大部分时间你都不会在意。可能有办法在不复制所有数据的情况下执行此操作。

4

你可以偷懒,并在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')) 

初始化模块将转换键一个时间上的需求,但如果你在访问符号版本后更新为重点的字符串版本价值,符号版本将不会更新。

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} 

你也可以拥有初始块未更新哈希值,这将保护你的那种错误的,但你仍然是脆弱的相反 - 更新版本化符号将不会更新字符串版本:

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} 

所以要小心这些事情是在两个关键形式之间切换。坚持一个。

260

下面是一个更好的方法,如果您使用的是Rails:

params。 symbolize_keys

结束。

如果你没有,就撕掉他们的代码(这也是在链接):

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

的链接已断开,但我可以证实,这个作品在导轨3.0.3 – 2011-01-28 16:06:53

+4

[to_options](HTTP:/ /apidock.com/rails/ActiveSupport/CoreExtensions/Hash/Keys/to_options)是[sybolize_keys]的一个别名(http://apidock.com/rails/ActiveSupport/CoreExtensions/Hash/Keys/symbolize_keys)。 – ma11hew28 2011-02-09 02:13:26

+41

不会象征嵌套散列。 – oma 2011-03-02 12:08:58

18

我真的很喜欢Mash宝石。

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

111

对于YAML的Ruby的特定情况下,如果键与“:”开始,他们将被自动扣留作为符号。

 
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 
2

如何:

my_hash = HashWithIndifferentAccess.new(YAML.load_file('yml')) 

# my_hash['key'] => "val" 
# my_hash[:key] => "val" 
10

params.symbolize_keys也会起作用。该方法将散列键变成符号并返回一个新的散列。

0
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} 
44

如果你使用Rails,它是非常简单的 - 你可以使用一个HashWithIndifferentAccess和访问键同时作为字符串和符号:

my_hash.with_indifferent_access 

还看到:

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


或者你可以使用宝石,其中包含真棒“红宝石微面” Ruby Core和Standard Library类的很多扩展。

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

57

更简洁:

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

这里有一个方法来深象征对象

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 
9

到@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 
3

一个较短的班轮FWIW:

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

这不正是一个班轮,但事实证明所有的字符串键为符号,还嵌套的:

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 
0

我喜欢这一行,当我不使用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} 

哈希#删除的回报,我们希望改变删除键

1

数组的值。

字符串= [ “HTML”, “CSS”, “JavaScript的”, “Python的”, “红宝石”]

创建一个新的变量作为一个空数组,所以我们可以 “.push” 中的符号。

符号= []

这里我们定义一个具有块的方法。

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

代码结束。

所以这可能是将字符串转换为数组中的符号的最直接的方式。创建一个字符串数组,然后创建一个新变量并将该变量设置为一个空数组。然后选择用“.each”方法创建的第一个数组中的每个元素。然后使用一个块代码来“刷新”新数组中的所有元素,并使用“.intern或.to_sym”将所有元素转换为符号。

符号更快,因为它们可以在代码中节省更多内存,并且只能使用它们一次。符号最常用于哈希键,这很好用。我不是最好的ruby程序员,但是这种形式的代码对我有很大帮助。如果有人知道更好的方法,请分享,也可以使用这种方法做hash!

2

这是谁使用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
  • 唯一密钥如果象征字符串手段丢失一些信息(覆盖哈希部分)提高一个RuntimeError
  • 象征也递归地包含散列
  • 返回符号化散列
  • 工作到位!
1

如果您想香草红宝石的解决方案,并为我不必ActiveSupport访问这里是深象征着溶液(非常类似于以前的)

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 
-2

symbolize_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 
7

所以很多答案,但一个方法轨功能hash.symbolize_keys

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 
0

Facets' Hash#deep_rekey一个衬里也是一个不错的选择,尤其是:

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

样品:

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

万一原因你需要做的,这是因为你的数据最初是从JSON来了,你可以通过在:symbolize_names选项时刚好路过跳过任何这种解析摄入JSON。需要

没有Rails和使用Ruby作品> 1.9

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

在红宝石我觉得这是把字符串键的哈希值,以符号的最简单和容易理解的方式:

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

对于散列中的每个关键字,我们称之为删除,将其从散列中删除(同时删除返回与被删除的关键字相关联的值),并立即将其设置为等于符号化关键字。

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

转换为:

{:g=>"a", 2=>{:v=>"b", :x=>{:z=>"c"}}} 
相关问题