如何判断哈希表中的键全部是符号还是字符串?

3
有没有一种快速检查哈希表中键值是符号还是字符串的方法?

1
你为什么需要知道这个?使用场景是什么?也许其他数据结构会更适合你的使用场景? - spickermann
1
Ruby不是一种类型化的语言,因此你要么需要提前了解你的数据,要么在运行时强制转换你的值。考虑到Hashie或Rails的特性,如HashWithIndifferentAccess,或者结构体对象,它们可以通过方法调用、字符串或符号来访问成员,很难猜测为什么这很重要。在Ruby中,对于大多数事情,考虑强制转换或鸭子类型而不是对象相等,你会更加快乐。 - Todd A. Jacobs
3个回答

3

TL;DR

一个只有单层键的平面哈希表可以很容易地被查询,但嵌套数据结构则不行。另外,哈希表的键并不仅限于字符串或符号键。你几乎可以使用任何 Ruby 对象作为哈希表的键,只需注意这些对象必须要 #respond_to? 一些特定方法才能正确地作为键。

使用 #keys.all?

如果你的哈希表不是嵌套的数据结构,那么你可以简单地询问该哈希表是否其所有顶级键都是符号对象:

p {foo: 1, bar: 2, baz: 3}.keys.all? Symbol
#=> true

如果你想要检查相反的情况,只需将Symbol替换为String
但是,如果你有嵌套的数据结构,那么你必须遍历每个键和值来将其符号化或字符串化。你可以使用类似 Hashie 的宝石,或者本地地往返于哈希和 JSON 之间,以强制将符号转换为字符串(默认)或在序列化或解析期间执行其他对象转换。例如,在 Ruby 3.1.2 中:
require "json"

hash = {foo: {bar: 1, baz: 2 }}
hash = JSON.parse hash.to_json

hash
#=> {"foo"=>{"bar"=>1, "baz"=>2}}

将确保将所有的键转换为字符串对象,如果无法合理地转换为字符串,则会引发异常。您还可以传递其他 选项 以强制执行不同的行为,包括支持各种 内置自定义 的 JSON 添加(如果需要)。与 YAML 或 Marshal 的往返也是可能的,尽管如果在哈希中有受污染或用户提供的对象,则通常比标准 JSON 更不安全。

1
您可以写以下内容。
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

例如,如果
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


1
你可以使用#all?方法来检查哈希表的所有键是否都是符号类型,代码如下所示:

#all?

hash = { foo: 1, bar: 2, baz: 3 }

hash.all? { |key, _value| key.is_a?(Symbol) }
#=> true

但是你上面的哈希不是基于符号的,而是基于字符串的。那么它是如何工作的呢? - user2939055
1
上面的示例中,哈希表使用符号作为键。如果使用字符串作为键,则该哈希表将如下所示:{ "foo" => 1, "bar" => 2, "baz" => 3 } - Zoran
有没有不需要迭代就能检查的方法? - user2939055
2
没有其他方法可以遍历所有键,因为键可以是任何对象,如字符串、符号、整数、复杂对象、类或其他任何东西。哈希表不关心并且不跟踪存储在哈希表中的键的类型。因此,您需要检查所有键。 - spickermann
诚然,这只是一个小问题,但为什么要分配*_value*然后将其丢弃呢?在一个非常大的哈希表中,这可能会对性能产生影响,尽管对于您的示例来说可能没有太大区别,但这是一个不必要的赋值。 - Todd A. Jacobs
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接