【问题标题】:Ruby Array of Hash parsingRuby Array 的 Hash 解析
【发布时间】:2018-04-30 19:53:27
【问题描述】:

我有一个 yaml 文件,格式为:

parameters:
  - param_name: age
    requires:
    - name
  - param_name: height
    requires:
    - name

基于这种格式,我想接受键和值的散列,并确定键和值的组合是否有效。例如基于上面的例子,如果有人提交了一个带有值的哈希:

{'age' => 15, 'height' => '6ft'}

它会被认为是无效的,因为参数名称是必需的。所以一个有效的提交看起来像

{'age' => 15, 'height' => '6ft', 'name' => 'Abe Lincoln'}.

基本上我想要的是这样的:

对于每个参数对象,如果它下面有一个 requires 数组。检查该数组中元素的所有参数 param_names,如果缺少退出。

我有一个非常丑陋的双循环来检查这个,但我想收紧代码。我想我可以使用块来验证我需要的数据。到目前为止,这是我想出的:

require 'yaml'
requirements = YAML.load_file('./require.yaml')
require_fields = Array.new

requirements['parameters'].each do |param|
  require_fields.concat(param['require']) if param.has_key? 'require'
end

require_fields.each do |requirement|
  found = false
  requirements['parameters'].each do |param|
    if param['param_name'] == requirement
      found = true
    end
  end
  abort "#{requirement} is a required field" unless found
end

【问题讨论】:

    标签: arrays ruby hash yaml block


    【解决方案1】:

    如果你让它更符合 Ruby 的习惯,你可以清理很多:

    require 'yaml'
    requirements = YAML.load_file('./require.yaml')
    
    require_fields = requirements['parameters'].select do |param|
      param.has_key?('require')
    end.map do |param|
      param['require']
    end
    
    require_fields.each do |requirement|
      found = requirements['parameters'].any? do |param|
        param['param_name'] == requirement
      end
    
      abort "#{requirement} is a required field" unless found
    end
    

    你也可以这样做:

    require_fields = requirements['parameters'].map do |param|
      param['require']
    end.compact
    

    只要您的require 是某物或nil,这可能就足够了。

    您还可以将该输入 YAML 转换为简单的依赖散列结构:

    dependencies = requirements.map do ||
      [ param['param_name'], param['requires'] ]
    end.to_h
    

    那么你就可以很容易地测试了:

    dependencies.each do |name, requirements|
      found = requirements.find do |required_name|
        !dependencies[required_name]
      end
    
      abort "#{found} is a required field" unless found
    end
    

    这是对您代码的非常粗略的改编,但我希望它能给您一些想法。

    【讨论】:

      【解决方案2】:

      我会进行后续检查、收集错误并立即报告:

      req = YAML.load 'parameters:
        - param_name: age
          requires:
          - name
        - param_name: height
          requires:
          - name'
      input = {'age' => 15, 'height' => '6ft'}
      
      req['parameters'].each_with_object([]) do |req, err|
        next unless input[req['param_name']] # nothing to check
        missed = req['requires'].reject { |param| input[param] }
        errors = missed.map do |param|
          [req['param_name'], param].join(' requires ')
        end
        err.concat(errors)
      end
      #⇒ ["age requires name", "height requires name"]
      

      或者,链接:

      req['parameters'].each_with_object(Hash.new { |h, k| h[k] = [] }) do |req, err|
        next unless input[req['param_name']] # nothing to check
      
        req['requires'].each do |param|
          err[param] << req['param_name'] unless input[param]
        end
      end.map do |missing, required|
        "Missing #{missing} parameter, required for: [#{required.join(', ')}]"
      end.join(',')
      #⇒ "Missing name parameter, required for: [age, height]"
      

      【讨论】:

        猜你喜欢
        • 2014-09-12
        • 2022-11-06
        • 1970-01-01
        • 1970-01-01
        • 2012-11-25
        • 2020-01-23
        • 2016-03-24
        • 1970-01-01
        • 2011-12-05
        相关资源
        最近更新 更多