我有一个数组数组,因为描述中需要将其转换为Ruby中的格式化哈希

时间:2018-07-11 18:19:10

标签: arrays ruby hash

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

[["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'"]]

我想要一个可以使它看起来像以下的红宝石代码:

{
  '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 个答案:

答案 0 :(得分:4)

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

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'"]]}

答案 1 :(得分:2)

这利用了将块传递到THIS GITHUB PAGE的作用,该块通过Hash::new将同一块传递给新的子哈希:

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

现在,我们可以迭代数组,并且我们知道每个子数组中的最后一个值都将成为最终值(即,不是子散列的最后一个值),其他所有操作都需要创建一个新的子哈希,这已经完成上面,当我们访问没有值的键时,因此我们可以使用default_proc访问所有中间键,我们还需要将所有键转换为符号,并且(出现)从开头删除单引号并值的结尾:

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"
      }
    }
  }
}

答案 2 :(得分:2)

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'"}}}}