题
什么(最快的/清洁/简单的)的方式把所有的钥匙在哈希从字符串中的符号的红宝石?
这将是方便的,当分析其.
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}
会将哈希值复制到一个新的哈希值。
其他提示
如果你使用Rails,这是一个更好的方法:
params。 symbolize_keys
结束。
如果你不是,那就去掉他们的代码(它也在链接中):
myhash.keys.each do |key|
myhash[(key.to_sym rescue key) || key] = myhash.delete(key)
end
对于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
更简洁:
Hash[my_hash.map{|(k,v)| [k.to_sym,v]}]
如果您正在使用Rails,它会更简单 - 您可以使用HashWithIndifferentAccess并以String和Symbols的形式访问键:
my_hash.with_indifferent_access
另见:
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}
从 Ruby 2.5.0
开始,您可以使用 Hash#transform_keys
或 Hash#transform_keys!
。
{'a' => 1, 'b' => 2}.transform_keys(&:to_sym) #=> {:a => 1, :b => 2}
http://api.rubyonrails.org/classes/Hash。 HTML#方法-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
我真的很喜欢 Mash gem。
您可以执行 mash ['key']
,或 mash [:key]
,或 mash.key
如果您正在使用json,并希望将其用作哈希,那么在核心Ruby中您可以这样做:
json_obj = JSON.parse(json_str, symbolize_names: true)
symbolize_names :如果设置为true,则返回JSON对象中名称(键)的符号。否则返回字符串。字符串是默认值。
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
{'g'=> 'a', 2 => {'v' => 'b', 'x' => { 'z' => 'c'}}}.deep_symbolize_keys!
转换为:
{:g=>"a", 2=>{:v=>"b", :x=>{:z=>"c"}}}
这里有很多答案,但一个方法rails函数是 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
如果原因你需要这样做是因为你的数据最初来自JSON,你可以通过传递:symbolize_names
选项来跳过任何解析在摄取JSON时。
不需要Rails并且可以使用Ruby&gt; 1.9
JSON.parse(my_json, :symbolize_names => true)
你可能很懒,把它包装在 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块会根据需要一次转换密钥,但如果在访问符号版本后更新密钥字符串版本的值,则不会更新符号版本。
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块不更新散列,这可以保护你免受这种错误的影响,但你仍然容易受到相反的攻击 - 更新符号版本不会更新字符串版本:
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}
因此要注意这些是在两种关键形式之间切换。坚持一个。
以下是否会有以下工作?
new_hash = Hash.new
my_hash.each { |k, v| new_hash[k.to_sym] = v }
它会复制哈希值,但大部分时间你都不会关心它。可能有一种方法可以在不复制所有数据的情况下完成。
my_hash.inject({}){|h,(k,v)| h.merge({ k.to_sym => v}) }
这个怎么样:
my_hash = HashWithIndifferentAccess.new(YAML.load_file('yml'))
# my_hash['key'] => "val"
# my_hash[:key] => "val"
这是谁的人使用 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
- 象征递归还包含哈希
- 返回的象征哈希
- 工作在地方!
我们想要更改的数组。
strings = [&quot; HTML&quot;,&quot; CSS&quot;,&quot; JavaScript&quot;,&quot; Python&quot;,&quot; Ruby&quot;]
将一个新变量设为空数组,以便我们可以“.push” 。中的符号。
symbols = []
这是我们用块定义方法的地方。
strings.each {| x | symbols.push(x.intern)}
代码结束。
所以这可能是在Ruby中将字符串转换为数组符号的最简单方法。创建一个字符串数组然后创建一个新变量并将该变量设置为一个空数组。然后选择使用“.each”创建的第一个数组中的每个元素。方法。然后使用块代码“.push”新数组中的所有元素并使用“.intern或.to_sym”;将所有元素转换为符号。
符号更快,因为它们可以在代码中保存更多内存,而且只能使用一次。符号最常用于哈希中的键,这很棒。我不是最好的红宝石程序员,但这种形式的代码对我帮助很大。如果有人知道更好的方法请分享,你也可以使用这种方法进行哈希!
如果你会喜欢香草的红宝石的解和作为我做不到 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
从精神 3.0开始,您可以添加 symbolize_names:选项
Psych.load(&quot; --- \ n foo:bar&quot;)
#=&gt; {&QUOT; FOO&QUOT; =&GT;&QUOT;栏&QUOT;} 代码>
Psych.load(&quot; --- \ n foo:bar&quot;,symbolize_names:true)
#=&gt; {:富=&GT;&QUOT; BAR&QUOT;} 代码>
注意:如果您的Psych版本低于3.0 symbolize_names:
将被默默忽略。
我的Ubuntu 18.04开箱即用,包含ruby 2.5.1p57
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}
这不是一个单行,但它将所有字符串键变为符号,也是嵌套符号:
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}
Hash#delete返回已删除密钥的值
面'哈希#deep_rekey 也是一个不错的选择,特别是:
- 如果你发现使用其他糖从方方面面在你的项目
- 如果你愿意代码的可读性超过cryptical一套。
示例:
require 'facets/hash/deep_rekey'
my_hash = YAML.load_file('yml').deep_rekey
在ruby中,我发现这是将哈希中的字符串键转换为符号的最简单易懂的方法:
my_hash.keys.each { |key| my_hash[key.to_sym] = my_hash.delete(key)}
对于散列中的每个键,我们在其上调用delete,将其从散列中删除(同时删除返回与已删除的键相关联的值),我们立即将其设置为等于符号化键。
类似于先前的解决方案而编写的一点不同。
- 这允许哈希嵌套的和/或有阵列。
- 得到转换的钥匙串作为奖励。
代码不会变异的散列已经过去了。
module HashUtils def symbolize_keys(hash) transformer_function = ->(key) { key.to_sym } transform_keys(hash, transformer_function) end def stringify_keys(hash) transformer_function = ->(key) { key.to_s } transform_keys(hash, transformer_function) end def transform_keys(obj, transformer_function) case obj when Array obj.map{|value| transform_keys(value, transformer_function)} when Hash obj.each_with_object({}) do |(key, value), hash| hash[transformer_function.call(key)] = transform_keys(value, transformer_function) end else obj end end end