如何在ruby中进行递归

时间:2013-10-28 11:05:52

标签: ruby recursion tree

我有哈希哈希显示为树,类似于路线。下面,我添加了一个预期结果和我得到的结果的例子。

哈希示例:

hash = {
          'movies' => {
            'action' => {
              '2007' => ['video1.avi', 'x.wmv'],
              '2008' => ['']
            },
            'comedy' => {
              '2007' => [],
              '2008' => ['y.avi']
            }
          },
          'audio' => {
            'rock' => {
              '2003' => [],
              '2004' => ['group', 'group1']
            }
          }
        }

我期待这个结果:

movies
movies\action
movies\action\2007
movies\action\2007\video1.avi
movies\action\2007\x.wmv
movies\action\2008
movies\comedy\2007
movies\comedy\2008
movies\comedy\2008\y.avi
audio
audio\rock\2003
audio\rock\2004
audio\rock\2004\group
audio\rock\2004\group1

以下是我制作的一些代码:

def meth(key, val)
  val.each do |key1, val1|
    puts "#{key}/#{key1}"
    meth(key1, val1) if val1
  end
end

hash.each do |key, val|
  puts key
  meth(key,val)
end

返回此结果:

movies
movies/action
action/2007
2007/video1.avi
2007/x.wmv
action/2008
2008/
movies/comedy
comedy/2007
comedy/2008
2008/y.avi
audio
audio/rock
rock/2003
rock/2004
2004/group
2004/group1

任何人都可以解释如何做到这一点吗?

更新

感谢您的回答。在这种情况下,我想出了使用此代码。提示是将key1设置为上一个结果。

def meth key, val
  val.each do |key1, val1|
    puts "#{key}/#{key1}"
    key1 = "#{key}/#{key1}"
    meth(key1, val1) if val1
  end
end

3 个答案:

答案 0 :(得分:2)

您可以将代码更改为:

def meth(key, val)
  val.each do |key1, val1|
    puts "#{key}/"
    if (val1 && val1.is_a?(Hash))
       meth(key1, val1)
    else
       puts "#{val1}"
    end
  end
end

你期望这个方法的工作方式不同,取决于它的调用位置,但事实并非如此。该方法无论在何处被调用都会做同样的事情(例如,如果它被自己调用)。

递归是将一个问题分解为较小的子问题的行为。总会有至少两个。在你的情况下,两个子问题是   - 打印两个值   - 打印密钥并迭代哈希

至少有一个子问题需要结束递归,否则会永远运行。在上面的例子中,第一个子问题结束了递归。

答案 1 :(得分:0)

您必须将路径跟踪为数组:

def meth key, val
  val.each do |key1, val1|
    puts key.join("/")+"/"+key1
    meth(key + [key1], val1) if val1
  end
end

meth [], root_of_hash

答案 2 :(得分:0)

当我有一个可以包含不同类型的类的嵌套结构时,我喜欢创建一个case语句,因此很容易定义在不同场景中会发生什么。

def print_tree(input, path=[])
    case input
      when Hash then  input.flat_map{|x,y| print_tree(y, path+[x])}
      when Array then input.empty? ? [path] : input.map{|x| path+[x]}
    end
end
puts print_tree(my_hash).map{|z|z.join('/')}