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

发布于 2024-11-30 10:41:49 字数 160 浏览 0 评论 0原文

Rails I18n 库将 YAML 文件转换为可使用 t() 函数通过点路径调用访问的数据结构。

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

有谁知道如何使用 Ruby Hash 来做到这一点?或者只能直接通过 YAML 对象实现?

The Rails I18n library transforms a YAML file into a data structure that is accessible via a dotted path call using the t() function.

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

Does anyone know how to do this with a Ruby Hash? Or is it only possible directly via a YAML object?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

素食主义者 2024-12-07 10:41:49

只需在路径中的一个点上分割并迭代它即可找到正确的哈希值?

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

Just split on a dot in the path and iterate over this to find the right hash?

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

Alternatively you can build a new hash by iterating recursively over the whole structure:

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
情绪操控生活 2024-12-07 10:41:49

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 步骤。

Ruby 2.3 introduces the dig method that looks into nested arrays/hashes, it returns nil when no data is found.

For example:

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)

Of course if your nested use string keys, the to_sym step is not needed.

一刻暧昧 2024-12-07 10:41:49

是的,我不认为这是内置的,其他任何地方。但我在我的一个项目中使用了这样的东西:

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

Yeah, I don't think that's built-in, anywhere else. But I use something like this in one of my projects:

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

And then call it like

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'])
旧伤还要旧人安 2024-12-07 10:41:49

我建议看一下这个要点:
https://gist.github.com/potatosalad/760726

它添加了内爆 和 explode 方法到 Hash 对象,将嵌套键转换为单级点路径键,反之亦然。

I would suggest taking a look at this gist:
https://gist.github.com/potatosalad/760726

It adds implode and explode methods to Hash object that transforms nested keys to single-level dotted path keys, and vice versa.

三生路 2024-12-07 10:41:49

还有一个 Gem keypath-ruby

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

查看代码(并猜测一下t 是),看起来你可以这样做:

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

There is a Gem too keypath-ruby

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

Looking at the code (and guessing a little about what t is), it looks like you can do this:

t.value_at_keypath('one.two.three.four')
软糖 2024-12-07 10:41:49

这段代码不仅允许点表示法遍历哈希,还允许方括号遍历带有索引的数组。它还避免了递归以提高效率。

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

This code not only allows dot notation to traverse a Hash but also square brackets to traverse Arrays with indices. It also avoids recursion for efficiency.

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

Example:

a = {"b" => {"c" => [0, [1, 42]]}}
a.key_path("b.c[-1][1]") # => 42
岛徒 2024-12-07 10:41:49

还有HashDot

HashDot 允许在哈希上使用点表示法语法。它比使用 OpenStruct 创建的对象更快、更容易遍历。

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

There is also HashDot.

HashDot allows dot notation syntax use on hashes. It is faster, and more traversable than an object created with OpenStruct.

a = {b: {c: {d: 1}}}
a.b.c.d => 1
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文