代码之家  ›  专栏  ›  技术社区  ›  Bharath M

我有一个数组,如描述中所述,需要在Ruby中将其转换为格式化散列

  •  0
  • Bharath M  · 技术社区  · 7 年前

    我有一个包含许多数组的文件,如下所示:

    [["default", "'drop'"],
    ["rule", "49", "action", "'accept'"],
    ["rule", "49", "description", "'This one is for'"],
    ["rule", "49", "destination", "address", "'1.2.3.4/20'"],
    ["rule", "50", "action", "'accept'"],
    ["rule", "50", "description", "'Once more'"],
    ["rule", "50", "destination", "address", "'1.2.3.5/20'"]]
    

    我想要一个Ruby代码,它可以使它看起来像:

    {
      'default': 'drop',
      'rule': { 
        '49': { 
          'destination': { 
            'address': '1.2.3.4/20' 
          },
          'action': 'accept', 
          'description': 'This one is for' 
        },
        '50': {
          'destination': {
            'address': '1.2.3.5/20'
          },
          'action': 'accept',
          'description': 'Once more'
        }
      }
    }
    

    我尝试了不同的方法,替换和保留只有最后一把或几把钥匙丢失。请帮帮我。

    3 回复  |  直到 7 年前
        1
  •  4
  •   Cary Swoveland    7 年前

    这是另一个递归解决方案。使用递归的一个优点是数组可以是任意大小的。

    arr = [
      ["default", "'drop'"],
      ["rule", "49", "action", "'accept'"],
      ["rule", "49", "description", "'This one is for'"],
      ["rule", "49", "destination", "address", "'1.2.3.4/20'"],
      ["rule", "50", "action", "'accept'"],
      ["rule", "50", "description", "'Once more'"], 
      ["rule", "50", "destination", "address", "'1.2.3.5/20'"]
    ]
    
    def recurse(arr)
      arr.group_by(&:first).transform_values do |a|
        a.map! { |r| r.drop(1) }
        a.size == 1 && a[0].size == 1 ? a[0][0] : recurse(a)
      end
    end
    
    recurse arr
      #=> { "default"=>"'drop'",
      #     "rule"=>{
      #       "49"=>{
      #         "action"=>"'accept'",
      #         "description"=>"'This one is for'",
      #         "destination"=>{"address"=>"'1.2.3.4/20'"}
      #       },
      #       "50"=>{
      #         "action"=>"'accept'",
      #         "description"=>"'Once more'",
      #         "destination"=>{"address"=>"'1.2.3.5/20'"}
      #       }
      #     }
      #   }
    

    注意第一步如下。

    arr.group_by(&:first)
      #=> {"default"=>[["default", "'drop'"]],
      #    "rule"=>[["rule", "49", "action", "'accept'"],
      #             ["rule", "49", "description", "'This one is for'"],
      #             ["rule", "49", "destination", "address", "'1.2.3.4/20'"],
      #             ["rule", "50", "action", "'accept'"],
      #             ["rule", "50", "description", "'Once more'"],
      #             ["rule", "50", "destination", "address", "'1.2.3.5/20'"]]}
    
        2
  •  2
  •   Simple Lime    7 年前

    这就利用了将块传递给 Hash::new 它通过 default_proc :

    output = Hash.new { |hash, key| hash[key] = Hash.new(&hash.default_proc) }
    

    现在,我们只需迭代数组,我们知道每个子数组中的最后一个值将成为最终值(即,不是子散列值),并且当我们访问一个没有值的键时,其他所有需要创建一个新的子散列(如上所述),这样我们就可以使用 Hash#dig ,我们还需要将所有键转换为符号,并且(看起来)从值的开头和结尾删除单引号:

    array.each_with_object(output) do |(*nesting, key, value), hash|
      hash = nesting.empty? ? hash : hash.dig(*nesting.map(&:to_sym))
    
      hash[key.to_sym] = value.gsub(/(\A\'|\'\z)/, '')
    end
    

    用它来运行 array 设置为您的输入数组,我们将得到以下结果:

    {
      :default => "drop",
      :rule => {
        :"49" => {
          :action => "accept",
          :description => "This one is for",
          :destination => {
            :address => "1.2.3.4/20"
          }
        },
        :"50" => {
          :action => "accept",
          :description => "Once more",
          :destination => {
            :address => "1.2.3.5/20"
          }
        }
      }
    }
    
        3
  •  2
  •   Lars Haugseth    7 年前
    class Hash
      def deep_store(keys, value)
        if keys.size > 1
          self[keys.first] ||= {}
          self[keys.first].deep_store keys[1..-1], value
        else
          self[keys.first] = value
        end
        self
      end
    end
    
    input = [
      ["default", "'drop'"],
      ["rule", "49", "action", "'accept'"],
      ["rule", "49", "description", "'This one is for'"],
      ["rule", "49", "destination", "address", "'1.2.3.4/20'"],
      ["rule", "50", "action", "'accept'"],
      ["rule", "50", "description", "'Once more'"],
      ["rule", "50", "destination", "address", "'1.2.3.5/20'"]
    ]
    
    result = input.each_with_object({}) do |(*keys, value), hash|
      hash.deep_store keys, value
    end
    
    puts result
    
    # => {"default"=>"'drop'", "rule"=>{"49"=>{"action"=>"'accept'", "description"=>"'This one is for'", "destination"=>{"address"=>"'1.2.3.4/20'"}}, "50"=>{"action"=>"'accept'", "description"=>"'Once more'", "destination"=>{"address"=>"'1.2.3.5/20'"}}}}