【问题标题】:ruby - adding keys for depth to each nested hash inside larger hashruby - 将深度键添加到较大散列中的每个嵌套散列
【发布时间】:2021-03-11 17:34:56
【问题描述】:

我正在尝试编写一个方法,该方法将嵌套散列作为输入并返回带有添加“深度”键的散列。所以,例如:

hash = { 
  a: 1,
  b: 2, 
  c: { d: { e: 3 } }
}

会返回:

{
  a: 1,
  b: 2,
  c: {
    d: {
      e: 3,
      depth: 2
    },
    depth: 1
  },
  depth: 0
}

这是我想出的一些代码,它适用于这种情况,或者任何其他深度不超过 2 的散列,但我以错误的方式处理它。我正在尝试弄清楚如何使它适用于任何深度。

def depth(hash)
  hash.values.to_a.map!{|elem| if elem.class==Hash; elem.values.to_a.map!{|el| el.class==Hash ? el[:depth] = 2 : elem}; elem[:depth] = 1; else; elem; end}
  hash[:depth] = 0
  p hash
end

您可以假设输入是哈希。谢谢:-)

【问题讨论】:

  • 为什么急于选择答案?您认为它无法改进吗?您不希望看到其他解决方案吗?您可以随时更改您的选择,但考虑到做出选择并不紧迫,简单地推迟决定不是更好吗?大多数提问者至少要等待几个小时,甚至更长的时间,让世界各地当时还在睡觉的成员有机会提供解决方案。

标签: ruby nested key


【解决方案1】:

与现有答案相似,但可能更惯用

def add_depth(hash, depth = 0)
  hash
    .transform_values { |v| v.is_a?(Hash) ? add_depth(v, depth + 1) : v }
    .merge(depth: depth)
end

它基本上和其他的一样,但是将新哈希的创建和迭代委托给 ruby​​ 核心,可以说是更优化的 可能会更好地优化虚拟机

【讨论】:

  • 根据偏好,您可以进一步简化并将 if 语句移出transform_values,方法是将其作为保护子句放在方法的顶部。 return hash unless hash.is_a?(Hash)
  • 不错@3limin4t0r :)
  • “更优化”?嗯。喜欢“怀孕更多”?
  • 喜欢“更好”。我真正的意思是,通过使用正确的核心方法(transform_values),ruby 解释器可能有机会以无法从外部完成的方式进行优化。
  • 嘿 StackOverflow 请添加选项以公开支持编辑。谢谢@3limin4t0r 做对了。
【解决方案2】:

如果你想返回一个带有深度值的散列,你可以试试这样:

def desc_hash(hash,depth=0)
  ret = {}
  hash.keys.each do |key|
    if hash[key].instance_of?(Hash)
      ret[key] = desc_hash(hash[key],depth+1)
    else
      ret[key] = hash[key]
    end
  end
  ret[:depth]=depth
  ret
end

以你的哈希为例:

2.7.2 :252 > desc_hash(hash)
 => {:a=>1, :b=>2, :c=>{:d=>{:e=>3, :depth=>2}, :depth=>1}, :depth=>0}

这是一个递归例程,将深度传递给自身,带有任何子哈希。

【讨论】:

  • instance_of? 不检测子类
【解决方案3】:

在这种情况下,我会使用递归解决方案,但管理您自己的堆栈的好处是您不会遇到SystemStackError (stack level too deep)

管理您自己的堆栈确实会使事情变得更复杂,但如果您的哈希嵌套非常深,则可能值得付出努力。

def depth(hash)
  with_depth = hash.merge({ depth: 0 })
  stack = [with_depth]

  while hash = stack.shift # or .pop
    hash.each_key do |key|
      next unless hash[key].is_a?(Hash)
      hash[key] = hash[key].merge({ depth: hash[:depth] + 1 })
      stack << hash[key]
    end
  end

  with_depth
end

【讨论】:

    【解决方案4】:

    如果我明白了,这是一个递归选项。

    给定哈希(我添加了更多深度):

    hash_ = { 
      a: 1,
      b: 2, 
      c: { d: { e: 3, f: {g: 4} } }
    }
    

    方法如下:

    def depth(hash_, deep=1, root=true)
      hash_[:depth] = 0 if root
      root = false
      hash_.each  do |k, v|
        if v.is_a? Hash
          v[:depth] = deep
          depth(v, deep+=1, root)
        end
      end
    end
    

    我不太喜欢root 开关,但这是我想到的第一个想法。

    所以你可以调用它并检查结果是否符合预期:

    depth(hash_)
    #=> {:a=>1, :b=>2, :c=>{:d=>{:e=>3, :f=>{:g=>4, :depth=>3}, :depth=>2}, :depth=>1}, :depth=>0}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-03
      • 2016-08-10
      • 2014-06-24
      • 2013-07-08
      • 2012-02-20
      • 1970-01-01
      • 2018-11-07
      • 1970-01-01
      相关资源
      最近更新 更多