使用点路径键字符串访问Ruby哈希表

14
Rails I18n库将一个YAML文件转换成一个可通过t()函数进行点路径调用的数据结构。
t('one.two.three.four')

有人知道如何使用 Ruby 哈希实现这个吗?还是只能通过 YAML 对象直接实现?
7个回答

25

只需在路径中按照点进行拆分,然后迭代此内容以查找正确的哈希值?

path.split(".").inject(hash) { |hash, key| hash[key] }

或者你可以通过递归地迭代整个结构来构建一个新的哈希表:

def convert_hash(hash, path = "")
  hash.each_with_object({}) do |(k, v), ret|
    key = path + k

    if v.is_a? Hash
      ret.merge! convert_hash(v, key + ".")
    else
      ret[key] = v
    end
  end
end

13
Ruby 2.3引入了dig方法,用于查找嵌套的数组/哈希表,当没有找到数据时,它会返回nil
例如:
test_data = {a: {b: {c: {d: 1}, e: 2}}}
path = 'a.b.c.d'.split('.').map(&:to_sym)
# path => [:a, :b, :c, :d]
test_data.dig(*path)

当然,如果您的嵌套使用字符串键,则不需要进行to_sym步骤。

11

是的,我认为那个功能没有内置到其他地方。但是在我的一个项目中,我使用类似于这样的东西:

class Hash
  def dig(dotted_path)
    parts = dotted_path.split '.', 2
    match = self[parts[0]]
    if !parts[1] or match.nil?
      return match
    else
      return match.dig(parts[1])
    end
  end
end

然后像这样调用它

my_hash = {'a' => {'b' => 'a-b', 'c' => 'a-c', 'd' => {'e' => 'a-d-e'}}, 'f' => 'f'}
my_hash.dig('a.d.e') # outputs 'a-d-e' (by calling my_hash['a']['d']['e'])

2
Ruby 2.3现在提供了一个类似的方法,它被准确地称为dig - David Costa

2

还有一个宝石,叫做keypath-ruby

gem 'key_path', :git => 'https://github.com/nickcharlton/keypath-ruby.git'

看着代码(猜测一下t是什么),你可以这样做:

t.value_at_keypath('one.two.three.four')

2

2

这段代码不仅允许使用点符号遍历哈希表,还允许使用带索引的方括号遍历数组。同时为了提高效率,它避免使用递归。

class Hash

  def key_path(dotted_path)
    result = self
    dotted_path.split('.').each do |dot_part|
      dot_part.split('[').each do |part|
        if part.include?(']')
          index = part.to_i
          result = result[index] rescue nil
        else
          result = result[part] rescue nil
        end
      end
    end

    result
  end

end

例子:

a = {"b" => {"c" => [0, [1, 42]]}}
a.key_path("b.c[-1][1]") # => 42

0

还有HashDot

HashDot允许在哈希上使用点符号语法。它比使用OpenStruct创建的对象更快,更易于遍历。

a = {b: {c: {d: 1}}}
a.b.c.d => 1

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