在ruby中转换数组的哈希

时间:2018-06-22 06:55:52

标签: arrays ruby hash

我有一个(大,超过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
      }
    }
  }
}

3 个答案:

答案 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. 创建无限嵌套的哈希。基本上,每当您搜索不存在的密钥时,该密钥就会关联一个空哈希。
  2. 对于每个键,挖掘到倒数第二个子键(除以.的结果),然后将值分配给挖掘的哈希的最后一个子键。

答案 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