首页 > 解决方案 > 如何将平面 Ruby 散列解析为嵌套散列?

问题描述

我有以下平面 Ruby 哈希:

{ 
  "builder_rule_0_filter"=>"artist_name", 
  "builder_rule_0_operator"=>"contains", 
  "builder_rule_0_value_0"=>"New Found Glory", 

  "builder_rule_1_filter"=>"bpm", 
  "builder_rule_1_operator"=>"less", 
  "builder_rule_1_value_0"=>"150", 

  "builder_rule_2_filter"=>"days_ago", 
  "builder_rule_2_operator"=>"less", 
  "builder_rule_2_value_0"=>"40", 

  "builder_rule_3_filter"=>"release_date_start", 
  "builder_rule_3_operator"=>"between", 
  "builder_rule_3_value_0"=>"2019-01-01", 
  "builder_rule_3_value_1"=>"2019-12-31", 
}

我想将其转换为更有条理/可用的嵌套哈希:

{
  "0"=>
    {
      "filter"=>"artist_name",
      "operator"=>"contains",
      "values"=>
      {
        "0"=>"New Found Glory"
      }
    },
  "1"=>
    {
      "filter"=>"bpm",
      "operator"=>"less",
      "values"=>
      {
        "0"=>"150"
      }
    }
  "2"=>
    {
      "filter"=>"days_ago",
      "operator"=>"less",
      "values"=>
      {
        "0"=>"40"
      }
    }
  "3"=>
    {
      "filter"=>"release_date_start",
      "operator"=>"between",
      "values"=>
      {
        "0"=>"2019-01-01"
        "1"=>"2019-12-31"
      }
    }
}

那么,如何转换平面哈希(我从表单中获取)并根据这些键名将其转换为嵌套?

标签: rubyhash

解决方案


首先,您可以根据前缀编号将散列拆分为多个散列(随意运行此命令以查看返回值)

groups = input.
  group_by { |k,v| k.match(/builder_rule_(\d+)/)[1] }.
  transform_values(&:to_h)

此时,如果您只使用一些硬编码来构建 key-valls,那么创建内部对象会更容易:

result = groups.each_with_object({}) do |(prefix, hash), memo|
  memo[prefix] = {
    "filter" => hash["builder_rule_#{prefix}_filter"],
    "operator" => hash["builder_rule_#{prefix}_operator"],
    "values" => hash.select do |key, val|
      key =~ /builder_rule_#{prefix}_value/
    end.sort_by { |key, val| key }.map { |(key, val)| val }
  }
end

可能会混淆什么.sort_by { |key, val| key }.map { |(key, val)| val }意思。我可以拼写出来:

  • hash.select { |key, val| key =~ /builder_rule_#{prefix}_value/ }获取将用于“值”数组的键值。它返回一个哈希。
  • .sort_by { |key, val| key }将散列转换为元组数组[key, val],按键排序。这是为了使这些值以正确的顺序出现。
  • .map { |(key, val)| val }将嵌套数组转换为单级数组,丢弃键

您也可以使用sort_by(&:first).map(&:second),尽管您需要积极的支持才能使用Array#second


推荐阅读