将哈希中所有键从字符串转换为Ruby中符号的(最快/最简洁/直接)方法是什么?将字符串转换为哈希中符号的最佳方法
这在解析YAML时会很方便。
my_hash = YAML.load_file('yml')
我希望能够使用:
my_hash[:key]
不是:
my_hash['key']
将哈希中所有键从字符串转换为Ruby中符号的(最快/最简洁/直接)方法是什么?将字符串转换为哈希中符号的最佳方法
这在解析YAML时会很方便。
my_hash = YAML.load_file('yml')
我希望能够使用:
my_hash[:key]
不是:
my_hash['key']
如果你想要一个班轮,
my_hash = my_hash.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
将哈希复制到一个新的钥匙象征。
看起来它应该对我有用,但是: 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
啊,抱歉不清楚 - 注入不会修改调用者。你需要做my_hash = my_hash.inject({}){| memo,(k,v)|备忘录[k.to_sym] = v;备忘录} – 2009-04-29 19:06:10
这正是我所期待的。我修改了一下,并添加了一些行,甚至可以在嵌套散列中创建符号。看看这里,如果你有兴趣:http://www.any-where.de/blog/ruby-hash-convert-string-keys-to-symbols/ – Matt 2009-08-19 14:57:56
会像下面这样的工作?
new_hash = Hash.new
my_hash.each { |k, v| new_hash[k.to_sym] = v }
它会复制哈希值,但大部分时间你都不会在意。可能有办法在不复制所有数据的情况下执行此操作。
你可以偷懒,并在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}
所以要小心这些事情是在两个关键形式之间切换。坚持一个。
下面是一个更好的方法,如果您使用的是Rails:
params。 symbolize_keys
结束。
如果你没有,就撕掉他们的代码(这也是在链接):
myhash.keys.each do |key|
myhash[(key.to_sym rescue key) || key] = myhash.delete(key)
end
的链接已断开,但我可以证实,这个作品在导轨3.0.3 – 2011-01-28 16:06:53
[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
不会象征嵌套散列。 – oma 2011-03-02 12:08:58
我真的很喜欢Mash宝石。
你可以做mash['key']
,或mash[:key]
,或mash.key
对于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
如何:
my_hash = HashWithIndifferentAccess.new(YAML.load_file('yml'))
# my_hash['key'] => "val"
# my_hash[:key] => "val"
params.symbolize_keys
也会起作用。该方法将散列键变成符号并返回一个新的散列。
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}
如果你使用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}
更简洁:
Hash[my_hash.map{|(k,v)| [k.to_sym,v]}]
这里有一个方法来深象征对象
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
到@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
一个较短的班轮FWIW:
my_hash.inject({}){|h,(k,v)| h.merge({ k.to_sym => v}) }
http://api.rubyonrails.org/classes/Hash.html#method-i-symbolize_keys
hash = { 'name' => 'Rob', 'age' => '28' }
hash.symbolize_keys
# => { name: "Rob", age: "28" }
这不正是一个班轮,但事实证明所有的字符串键为符号,还嵌套的:
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}
哈希#删除的回报,我们希望改变删除键
字符串= [ “HTML”, “CSS”, “JavaScript的”, “Python的”, “红宝石”]
符号= []
strings.each {| x | symbols.push(x.intern)}
所以这可能是将字符串转换为数组中的符号的最直接的方式。创建一个字符串数组,然后创建一个新变量并将该变量设置为一个空数组。然后选择用“.each”方法创建的第一个数组中的每个元素。然后使用一个块代码来“刷新”新数组中的所有元素,并使用“.intern或.to_sym”将所有元素转换为符号。
符号更快,因为它们可以在代码中节省更多内存,并且只能使用它们一次。符号最常用于哈希键,这很好用。我不是最好的ruby程序员,但是这种形式的代码对我有很大帮助。如果有人知道更好的方法,请分享,也可以使用这种方法做hash!
这是谁使用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
如果您想香草红宝石的解决方案,并为我不必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
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
所以很多答案,但一个方法轨功能hash.symbolize_keys
这是我的嵌套哈希
def symbolize_keys(hash)
hash.each_with_object({}) { |(k, v), h| h[k.to_sym] = v.is_a?(Hash) ? symbolize_keys(v) : v }
end
Facets' Hash#deep_rekey一个衬里也是一个不错的选择,尤其是:
样品:
require 'facets/hash/deep_rekey'
my_hash = YAML.load_file('yml').deep_rekey
万一原因你需要做的,这是因为你的数据最初是从JSON来了,你可以通过在:symbolize_names
选项时刚好路过跳过任何这种解析摄入JSON。需要
没有Rails和使用Ruby作品> 1.9
JSON.parse(my_json, :symbolize_names => true)
在红宝石我觉得这是把字符串键的哈希值,以符号的最简单和容易理解的方式:
my_hash.keys.each { |key| my_hash[key.to_sym] = my_hash.delete(key)}
对于散列中的每个关键字,我们称之为删除,将其从散列中删除(同时删除返回与被删除的关键字相关联的值),并立即将其设置为等于符号化关键字。
{'g'=> 'a', 2 => {'v' => 'b', 'x' => { 'z' => 'c'}}}.deep_symbolize_keys!
转换为:
{:g=>"a", 2=>{:v=>"b", :x=>{:z=>"c"}}}
由于Ruby 2.5.0
可以使用Hash#transform_keys
或Hash#transform_keys!
。
{'a' => 1, 'b' => 2}.transform_keys(&:to_sym) #=> {:a => 1, :b => 2}
[dup](http://stackoverflow.com/q/8379596/119790)? – 2012-05-11 14:38:44
如果您使用的是Rails,则使用`hash.symbolize_keys`和`hash.deep_symbolize_keys`来完成这项工作。 – Zaz 2014-08-06 17:17:34
Josh如果你会把你的评论放入一个答案,我会投票给你。需要'rails'; hash.deep_symbolize_keys在irb或pry中工作得很好。 :D – 2015-02-07 10:17:36