如何使用字符串描述从hash-within-hash结构中访问数据?

时间:2016-04-29 15:02:20

标签: ruby

我有以下内容:

data_spec['data'] = "some.awesome.values"

data_path = ""
data_spec['data'].split('.').each do |level|
  data_path = "#{data_path}['#{level}']"
end

data = "site.data#{data_path}"

此时,data等于字符串:"site.data['some']['awesome']['values']"

我需要帮助的是使用字符串来获取值:site.data['some']['awesome']['values']

site.data具有以下值:

{  
    "some" => {  
        "awesome" => {  
            "values" => [  
                {  
                    "things" => "Stuff",
                    "stuff" => "Things",
                },
                {  
                    "more_things" => "More Stuff",
                    "more_stuff" => "More Things",
                }
            ]
        }
    }
}

非常感谢任何帮助。谢谢!

4 个答案:

答案 0 :(得分:4)

如果您使用的是ruby 2.3.0(这很棒且我甚至不知道存在),您可以像tadman建议的那样使用site.data.dig('some', 'awesome', values')。这可能是您的最佳选择。但如果您真的想自己编写代码,请阅读以下内容。

你走在正确的轨道上,最好的方法是:

data_spec['data'] = "some.awesome.values"

data = nil
data_spec['data'].split('.').each do |level|
  if data.nil?
    data = site.data[level]
  else
    data = data[level]
  end
end

为了理解为什么这首先有用,你需要理解site.data['some']['awesome']['values']与说法相同:首先得到some然后在得到awesome里面然后得到values 。所以我们的第一步是检索some。由于我们没有第一级,但我们从site.data获取并将其保存到变量data。一旦我们掌握了数据,我们就可以从数据中获取每个级别并将其保存到数据中,从而使我们能够更深入地了解哈希值。

因此,使用您的示例data最初会如下所示:

        {"awesome" => {  
            "values" => [  
                {  
                    "things" => "Stuff",
                    "stuff" => "Things",
                },
                {  
                    "more_things" => "More Stuff",
                    "more_stuff" => "More Things",
                }
            ]
        }
    }

然后这个:

        {"values" => [  
            {  
                "things" => "Stuff",
                "stuff" => "Things",
            },
            {  
                "more_things" => "More Stuff",
                "more_stuff" => "More Things",
            }
        ]
    }

最后输出如下:

        [  
            {  
                "things" => "Stuff",
                "stuff" => "Things",
            },
            {  
                "more_things" => "More Stuff",
                "more_stuff" => "More Things",
            }
        ]

答案 1 :(得分:4)

如果您收到类似'x.y.z'的字符串并需要导航嵌套哈希,Ruby 2.3.0包含dig方法:

spec = "some.awesome.values"

data = {  
  "some" => {  
    "awesome" => {  
        "values" => [
          'a','b','c'
        ]
    }
  }
}

data.dig(*spec.split('.'))
# => ["a", "b", "c"]

如果您没有Ruby 2.3.0并且升级不是一个选项,您可以暂时修补它:

class Hash
  def dig(*path)
    path.inject(self) do |location, key|
      location.respond_to?(:keys) ? location[key] : nil
    end
  end
end

答案 2 :(得分:0)

我写了一些确实如此的东西。随意从中获取任何有价值的信息或窃取它! :)

https://github.com/keithrbennett/trick_bag/blob/master/lib/trick_bag/collections/collection_access.rb

查看单元测试以了解如何使用它:

https://github.com/keithrbennett/trick_bag/blob/master/spec/trick_bag/collections/collection_access_spec.rb

有一个返回lambda的accessor方法。由于可以使用[]运算符(方法,实际上)调用lambdas,因此可以获得这样的lambda并访问任意数量的级别:

accessor['hostname.ip_addresses.0']

或者,在您的情况下:

require 'trick_bag'
accessor = TrickBag::CollectionsAccess.accessor(site.data)
do_something_with(accessor['some.awesome.values'])

答案 3 :(得分:-2)

您正在寻找的东西通常被低估并且有充分的理由。但是你去了 - 它被称为eval

binding.eval data