将字符串转换为哈希符号的最佳方法

Bry*_* M. 241 ruby hashmap

什么是(最快/最干净/直接)的方式将哈希中的所有键从字符串转换为符号?

解析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)

  • 不会象征嵌套的哈希. (45认同)
  • [deep_symbolize_keys!(http://api.rubyonrails.org/classes/Hash.html#method-i-deep_symbolize_keys-21).在轨道2+上工作 (23认同)
  • 对于那些好奇的如何做反向,`hash.stringify_keys`有效. (13认同)
  • [to_options](http://apidock.com/rails/ActiveSupport/CoreExtensions/Hash/Keys/to_options)是[sybolize_keys]的别名(http://apidock.com/rails/ActiveSupport/CoreExtensions/Hash/Keys/ symbolize_keys). (6认同)
  • 我用新的&working(Rails 3)URL将链接切换到`symbolize_keys`.我最初修改了`to_options`的URL,但该链接没有文档.`symbolize_keys`实际上有描述,所以我用它来代替. (3认同)
  • `my_hash = my_hash.deep_symbolize_keys`在Rails 3上为我工作.谢谢@mastaBlasta! (3认同)
  • [您可以在任何Ruby项目中加载ActiveSupport核心扩展](http://edgeguides.rubyonrails.org/active_support_core_extensions.html),而不仅仅是rails:`require'active_support/core_ext/hash'` (2认同)

Sar*_*Mei 220

如果你想要一个单线,

my_hash = my_hash.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
Run Code Online (Sandbox Code Playgroud)

将符号化的键复制到新的哈希值.

  • 在Ruby 1.9中你可以像这样使用`each_with_object`:`my_hash.each_with_object({}){|(k,v),h | h [k.to_sym] = v}` (36认同)
  • @BryanM.我很晚才进入这个讨论:-)但你也可以使用`.tap`方法来消除最后传递`memo`的需要.我已经创建了所有解决方案的清理版本(也是递归的)https://gist.github.com/Integralist/9503099 (8认同)
  • 这不处理递归哈希...查找一次性但不是DRY. (7认同)
  • 啊,抱歉不清楚 - 注入不会修改来电者.你需要做my_hash = my_hash.inject({}){| memo,(k,v)| 备忘录[k.to_sym] = v; 备忘录} (5认同)
  • 这正是我想要的.我修改了一下并添加了一些线来甚至在嵌套的哈希中创建符号.如果你有兴趣,请看看这里:http://www.any-where.de/blog/ruby-hash-convert-string-keys-to-symbols/ (4认同)

小智 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

  • 甜!有没有办法将`YAML#load_file`设置为默认所有键符号而不是字符串w/o必须用冒号开始每个键? (15认同)

Mic*_*ton 61

更简洁:

Hash[my_hash.map{|(k,v)| [k.to_sym,v]}]
Run Code Online (Sandbox Code Playgroud)

  • 更易读的版本:`my_hash.map {| k,v | [k.to_sym,v]} .to_h` (14认同)
  • 它不代表嵌套的哈希. (11认同)
  • 这似乎是明显的选择. (5认同)

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

  • 实际上恰恰相反.它从符号转换为字符串.要转换为符号,请使用my_hash.symbolize_keys (2认同)

Sag*_*dya 48

既然Ruby 2.5.0你可以使用Hash#transform_keysHash#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)


yka*_*ich 20

我真的很喜欢Mash宝石.

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

  • 那是一个非常酷的宝石!使哈希工作非常舒适.谢谢你! (2认同)

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


Jae*_*Cho 12

params.symbolize_keys也会工作.此方法将哈希键转换为符号并返回新哈希.

  • 该方法不是核心Ruby.这是一个Rails方法. (26认同)

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)


Jay*_*Jay 9

{'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)

  • `deep_symbolize_keys`被添加到Rails的[Hash](http://api.rubyonrails.org/classes/Hash.html#method-i-deep_symbolize_keys)扩展中,但它不是Ruby核心的一部分。 (3认同)

sha*_*how 7

这里有很多答案,但是rails函数的一种方法是 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
Run Code Online (Sandbox Code Playgroud)


ram*_*ion 5

你可以偷懒,把它包装在一个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)

所以要注意这些是在两个关键形式之间切换。坚持一个。


Ada*_*ant 5

万一您需要执行此操作的原因是因为您的数据最初来自JSON,则可以通过在:symbolize_names导入JSON时仅传递选项来跳过任何解析。

不需要Rails,并且可以与Ruby> 1.9一起使用

JSON.parse(my_json, :symbolize_names => true)
Run Code Online (Sandbox Code Playgroud)