Ruby嵌套哈希键

问题描述 投票:2回答:2

我正在使用ClosureTree宝石在轨道上使用红宝石。我有一个嵌套的哈希,说

{
  :a00=>{
    :a10=>{
      :a20=>{}, 
      :a21=>{}
    }, 
    :a11=>{
      :a22=>{
        :a30=>{}, 
        :a31=>{}
      }
    }
  }
}

在此嵌套哈希中,我想找到任何给定键及其所有“超级键”的值。例如,对于:a30,我想找到其值{}以及嵌套在其中的哈希键:[:a00, :a11, :a22]

我发现了this article,它描述了一种满足我的准则的第一部分(查找键的值)的漂亮方法:

def deep_find(obj, key)
  return obj[key] if obj.respond_to?(:key?) && obj.key?(key)

  if obj.is_a? Enumerable
    found = nil
    obj.find { |*a| found = deep_find(a.last, key) }

    found
  end
end

但是,经过数小时的尝试,我仍然无法找到一种找到它们“超级钥匙”的方法。非常感谢您对此问题的帮助!

ruby-on-rails ruby hash
2个回答
2
投票

我会选择这样的东西:

def find_node_path(tree, search_key)
  return unless tree.is_a?(Hash)
  return [] if tree.key?(search_key)

  tree.each do |key, node|
    path = find_node_path(node, search_key)
    return [key, *path] if path
  end

  nil
end

path = find_node_path(tree, :a30)
#=> [:a00, :a11, :a22]

# retrieve value
value = tree.dig(*path, :a30)
#=> {}

这将执行以下操作,如果当前nil不是哈希,或者如果在当前tree结构中找不到search_key,它将返回tree

该方法遍历哈希的所有键/值对,并递归调用find_node_path。如果返回nil,则表示找不到search_key,因此跳到循环中的下一个迭代。

如果返回值不是nil,则意味着相对于search_key,在path中的node处找到了tree。在这种情况下,请在path之前加上当前迭代的key,然后将其返回。

注:尽管如果search_key在结构中不是唯一的,则此解决方案也有效。它只会返回找到的第一个匹配项。由于此解决方案使用depth first,因此当[:a1, :a2]设为tree = {a1: {a2: {a3: {}}}, b1: {a3: {}}}时它将返回search_key = :a3


0
投票
def extract(h,target_key)
  return [target_key, h[target_key]] if h.key?(target_key)
  h.each do |kk,v|
    next unless v.is_a?(Hash)
    arr = extract(v,target_key) 
    return [kk,*arr] unless arr.nil?
  end
  nil
end

h = {
  :a00=>{
    :a10=>{
      :a20=>{1=>2}, 
      :a21=>{3=>4}
    }, 
    :a11=>{
      :a22=>{
        :a30=>{5=>6}, 
        :a31=>{7=>8}
      }
    }
  }
}

[:a00, :a10, :a20, :a21, :a11, :a22, :a30, :a31, :a32].each do |k|
  puts ":#{k} -> #{extract(h,k) || "nil"}"
end

target_key -> extract(h, target_key)

:a00 -> [:a00, {:a10=>{:a20=>{1=>2}, :a21=>{3=>4}},
                :a11=>{:a22=>{:a30=>{5=>6}, :a31=>{7=>8}}}}]
:a10 -> [:a00, :a10, {:a20=>{1=>2}, :a21=>{3=>4}}]
:a20 -> [:a00, :a10, :a20, {1=>2}]
:a21 -> [:a00, :a10, :a21, {3=>4}]
:a11 -> [:a00, :a11, {:a22=>{:a30=>{5=>6}, :a31=>{7=>8}}}]
:a22 -> [:a00, :a11, :a22, {:a30=>{5=>6}, :a31=>{7=>8}}]
:a30 -> [:a00, :a11, :a22, :a30, {5=>6}]
:a31 -> [:a00, :a11, :a22, :a31, {7=>8}]
:a32 -> nil
© www.soinside.com 2019 - 2024. All rights reserved.