我有一个包含许多数组的文件,如下所示:
[["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'
}
}
}
我尝试了不同的方法,该方法正在替换并仅保留最后一个或几个键。请帮助我。
答案 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'"}}}}