【问题标题】:Access Ruby Hash Using Dotted Path Key String使用点分路径键字符串访问 Ruby 哈希
【发布时间】:2011-10-31 15:41:50
【问题描述】:

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

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

有谁知道如何使用 Ruby 哈希来做到这一点?还是只能通过 YAML 对象直接实现?

【问题讨论】:

    标签: ruby-on-rails ruby hash key yaml


    【解决方案1】:

    只需在路径中的一个点上拆分并对其进行迭代以找到正确的哈希?

    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
    

    【讨论】:

      【解决方案2】:

      Ruby 2.3 引入了dig method,它查看嵌套数组/哈希,当没有找到数据时返回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 步骤。

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

        • 现在 Ruby 2.3 中提供了一个类似的方法,它的名字正好是 dig
        【解决方案4】:

        也有宝石keypath-ruby

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

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

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

        【讨论】:

          【解决方案5】:

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

          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
          

          【讨论】:

            【解决方案6】:

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

            它将implodeexplode 方法添加到Hash 对象,将嵌套键转换为单级虚线路径键,反之亦然。

            【讨论】:

              【解决方案7】:

              还有HashDot

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

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2014-10-21
                • 2023-03-12
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-07-13
                相关资源
                最近更新 更多