我有一个(大,超过850个条目)带有以下键的哈希:
{
"asserts.regular" => 0,
"asserts.warning" => 0,
"asserts.msg" => 0,
"asserts.user" => 0,
"asserts.rollovers" => 0,
"connections.current" => 29,
"connections.available" => 51171,
"connections.totalCreated" => 489,
"metrics.commands.aggregate.failed" => 0,
"metrics.commands.aggregate.total" => 2029,
"metrics.commands.appendOplogNote.failed" => 0,
"metrics.commands.appendOplogNote.total" => 0,
"metrics.commands.applyOps.failed" => 0,
"metrics.commands.applyOps.total" => 0,
"metrics.commands.authSchemaUpgrade.failed" => 0,
"metrics.commands.authSchemaUpgrade.total" => 0,
"metrics.commands.authenticate.failed" => 0,
"metrics.commands.authenticate.total" =>0
}
条目的深度是动态的。
我想将其变成这样的哈希(为简洁起见,省略了一些键):
{
asserts: {
regular: 0,
warning: 0,
msg: 0
},
connections: {
current: 29
},
metrics: {
commands: {
aggregate: {
failed: 0
},
authenticate: {
failed: 0
}
}
}
}
答案 0 :(得分:4)
result = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
hash.each do |key, value|
*nesting, leaf = key.split('.').map(&:to_sym)
result.dig(*nesting)[leaf] = value
end
result
想法是:
.
的结果),然后将值分配给挖掘的哈希的最后一个子键。答案 1 :(得分:3)
h.each.with_object({}) { |(k, v), r|
k.split('.').map(&:to_sym).tap { |*f, l|
f.inject(r) { |t, p|
t[p] ||= {}
}[l] = v
}
}
编辑:有点晚了,看看ndn的答案,这是相同的想法,只是没有dig
,并且是功能齐全的样式...
答案 2 :(得分:0)
另一种有趣的方式来解决问题
h.transform_keys{|k| k.split('.').map(&:intern)}.each_with_object({}) do |((*a,l),v),obj|
a.reduce(obj) {|memo,k| memo[k] ||= {}}[l] = v
end
# If ruby < 2.4
h.map { |k,v| [k.split('.').map(&:intern),v]}.each_with_object({}) do |((*a,l),v),obj|
a.reduce(obj) {|memo,k| memo[k] ||= {}}[l] = v
end