如何判断哈希的键是都是符号还是字符串?



是否有一种方法可以快速检查哈希是否作为符号或字符串作为键?

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

最新更新