【问题标题】:print out Hash key and value pairs recursively递归打印哈希键和值对
【发布时间】:2016-08-23 12:46:24
【问题描述】:

我正在尝试定义一个函数,它可以以树格式打印出任何哈希值。该函数将执行以下操作:

来自

{"parent1"=>
    {"child1" => { "grandchild1" => 1,
                "grandchild2" => 2},
    "child2" => { "grandchild3" => 3,
                "grandchild4" => 4}}
}

   parent1:
        child1: 
              grandchild1:1
              grandchild2:2
        child2:
              grandchild3:3
              grandchild4:4

到目前为止,这是我的代码:

def readprop(foo)
    level = ''
    if foo.is_a?(Hash)
        foo.each_key {|key| if foo[key].nil? == false
                puts level + key + ":"
                level += "   "
                readprop(foo[key])
            end 
        }
    else
        puts level + foo
        level = level[0,level.length - 2]
    end
end 

它会给我一个像这样的错误格式:

parent1:
child1:
grandchild1:
1
   grandchild2:
2
   child2:
grandchild3:
3
   grandchild4:
4

【问题讨论】:

  • 你需要 YAML 的输出吗?
  • @sagarpandya82 不是真的,只是纯文本,我希望它们在网页上打印出来

标签: ruby


【解决方案1】:

你快到了。解决它的一种方法是使level 成为递归函数参数的一部分。 x 是问题中的哈希值。

简单的递归版本:

def print_hash(h,spaces=4,level=0)
  h.each do |key,val|
    format = "#{' '*spaces*level}#{key}: "
    if val.is_a? Hash
      puts format
      print_hash(val,spaces,level+1)
    else
      puts format + val.to_s
    end
  end
end

print_hash(x)

#parent1: 
#    child1: 
#        grandchild1: 1
#        grandchild2: 2
#    child2: 
#        grandchild3: 3
#        grandchild4: 4

在这种情况下,您也可以将其转换为 YAML(如上面评论中所述)

require 'YAML'
puts x.to_yaml
#---
#parent1:
#  child1:
#    grandchild1: 1
#    grandchild2: 2
#  child2:
#    grandchild3: 3
#    grandchild4: 4

【讨论】:

  • 非常感谢,这很完美,我也发现了我的代码的问题,我每次调用函数时都会初始化变量level,再次感谢您
【解决方案2】:

我会使用递归,但有些人可能会感兴趣的另一种方式。下面我使用“漂亮的打印机”awesome-print 进行部分格式化(特别是缩进),将结果保存到字符串,然后将几个gsub's 应用于字符串以按摩结果转换为所需的格式。

假设你的哈希值如下:

h = { "parent1"=>
        { "child1" => { "grandchild11" => 1,
                        "grandchild12" => { "great grandchild121" => 3 } },
          "child2" => { "grandchild21" => { "great grandchild211" =>
                                           { "great great grandchild2111" => 4 } },
                        "grandchild22" => 2 }
        }
    }

然后我们可以执行以下操作。

require 'awesome_print'

puts str = h.awesome_inspect(indent: -5, index: false, plain: true).
  gsub(/^\s*(?:{|},?)\s*\n|[\"{}]/, '').
  gsub(/\s*=>\s/, ':')

打印

 parent1:
      child1:
           grandchild11:1,
           grandchild12:
                great grandchild121:3
      child2:
           grandchild21:
                great grandchild211:
                     great great grandchild2111:4
           grandchild22:2 

步骤:

str = h.awesome_inspect(indent: -5, index: false, plain: true)

puts str 打印

{
     "parent1" => {
          "child1" => {
               "grandchild11" => 1,
               "grandchild12" => {
                    "great grandchild121" => 3
               }
          },
          "child2" => {
               "grandchild21" => {
                    "great grandchild211" => {
                         "great great grandchild2111" => 4
                    }
               },
               "grandchild22" => 2
          }
     }
}

s1 = str.gsub(/^\s*(?:{|},?)\s*\n|[\"{}]/, '')

puts s1 打印

 parent1 => 
      child1 => 
           grandchild11 => 1,
           grandchild12 => 
                great grandchild121 => 3
      child2 => 
           grandchild21 => 
                great grandchild211 => 
                     great great grandchild2111 => 4
           grandchild22 => 2

s2 = s1.gsub(/\s*=>\s/, ':')

puts s2 打印上面的结果。

【讨论】:

    【解决方案3】:

    不完全符合您的要求,但我会提交此答案,因为我认为您可能会发现它很有用:

    require 'yaml'
    
    hash = {"parent1"=> {"child1" => { "grandchild1" => 1,"grandchild2" => 2},
                         "child2" => { "grandchild3" => 3,"grandchild4" => 4}}}
    
    puts hash.to_yaml
    

    打印:

    ---
    parent1:
      child1:
        grandchild1: 1
        grandchild2: 2
      child2:
        grandchild3: 3
        grandchild4: 4
    

    【讨论】:

    • 是的,这也很有用,因为我对 Yaml 不是很熟悉。非常感谢
    【解决方案4】:

    Ruby Recursive Tree

    假设我们有

    #$ mkdir -p foo/bar
    #$ mkdir -p baz/boo/bee
    #$ mkdir -p baz/goo
    

    我们可以得到

    {
      "baz"=>{
        "boo"=>{
          "bee"=>{}},
        "goo"=>{}},
      "foo"=>{
        "bar"=>{}}}
    

    我们可以如下遍历树。所以,这里有一种基于磁盘上的目录树生成哈希的方法:

    Dir.glob('**/*'). # get all files below current dir
      select{|f|
        File.directory?(f) # only directories we need
      }.map{|path|
        path.split '/' # split to parts
      }.inject({}){|acc, path| # start with empty hash
        path.inject(acc) do |acc2,dir| # for each path part, create a child of current node
          acc2[dir] ||= {} # and pass it as new current node
        end
        acc
      }
    

    感谢 Mladen Jablanović 对此概念的另一个回答。

    【讨论】:

    • 谢谢@Munstasir Alam,但我只需要处理给定的哈希,不需要处理路径,就像这样Javascript post
    猜你喜欢
    • 1970-01-01
    • 2013-09-30
    • 1970-01-01
    • 1970-01-01
    • 2011-10-27
    • 1970-01-01
    • 2015-04-25
    • 2014-11-30
    • 2014-06-02
    相关资源
    最近更新 更多