是否有一种方法可以快速检查哈希是否作为符号或字符串作为键?
TL;DR
具有单一级别键的平面哈希可以很容易地被查询,但嵌套的数据结构则不能。此外,哈希键不仅限于字符串或符号键。您几乎可以使用任何Ruby对象作为Hash键,但需要注意对象必须#respond_to哪些方法。
使用# keys.all?
如果你的哈希不是一个嵌套的数据结构,那么你可以简单地问哈希是否所有的顶级键都是Symbol对象:
p {foo: 1, bar: 2, baz: 3}.keys.all? Symbol
#=> true
如果您想检查相反的情况,只需将Symbol
替换为String
。
但是,如果您有嵌套的数据结构,那么您必须遍历每个键和值以对每个键进行符号化或字符串化。您可以使用像Hashie这样的gem来实现这一点,或者本机往返于JSON的Hash以将符号强制转换为字符串(默认值),或者在序列化或解析期间执行其他对象转换。例如,对于Ruby 3.1.2:
require "json"
hash = {foo: {bar: 1, baz: 2 }}
hash = JSON.parse hash.to_json
hash
#=> {"foo"=>{"bar"=>1, "baz"=>2}}
将确保您的所有键都转换为String对象,或者在它们不能合理地转换为String时引发异常。您还可以传递其他选项来强制执行不同的行为,包括支持各种内置或自定义JSON添加(如果需要)。也可以使用YAML或Marshal进行往返,尽管如果您的Hash中有受污染或用户提供的对象,这些通常不如标准JSON安全。
可以使用#all?检查哈希的键是否都是符号,如下所示:
hash = { foo: 1, bar: 2, baz: 3 }
hash.all? { |key, _value| key.is_a?(Symbol) }
#=> true
你可以这样写:
def key_type(h)
case h.each_key.map(&:class).uniq
when [String] then String
when [Symbol] then Symbol
else nil
end
end
key_type('cats'=>9, 'dogs'=>2) #=> String
key_type(:cats=>9, :dogs=>2) #=> Symbol
key_type('cats'=>9, :dogs=>2) #=> nil
key_type(:cats=>9, 'dogs'=>2) #=> nil
key_type(9=>'cats') #=> nil
key_type(9=>'cats', 2=>'dogs') #=> nil
key_type({}) #=> nil
例如,if
h = { 'cats'=>9, 'dogs'=>2 }
然后
a = h.each_key.map(&:class)
#=> [String, String]
b = a.uniq
#=> [String]
返回String
。相反,如果
h = { 'cats'=>9, :dogs=>2 }
然后
a = h.each_key.map(&:class)
#=> [String, Symbol]
b = a.uniq
#=> [String, Symbol]
返回nil
。