Ruby:标准递归模式

时间:2012-05-21 07:25:35

标签: ruby recursion design-patterns

我常常在ruby中加入的一个东西是递归模式。例如,假设我有一个数组,并且可能包含数组作为无限深度的元素。所以,例如:

my_array = [1, [2, 3, [4, 5, [6, 7]]]]

我想创建一个可以将数组展平为[1, 2, 3, 4, 5, 6, 7]的方法。

我知道.flatten可以完成这项工作,但这个问题是我经常遇到的递归问题的一个例子 - 因此我试图找到一个更可重用的解决方案。

简而言之 - 我猜这种东西有一个标准模式,但我无法想出任何特别优雅的东西。任何想法赞赏

3 个答案:

答案 0 :(得分:5)

递归是一种方法,它不依赖于语言。您在编写算法时考虑了两种情况:再次调用函数的函数(递归情况)和破坏它的函数(基本情况)。例如,在Ruby中进行递归展平:

class Array
  def deep_flatten
    flat_map do |item|
      if item.is_a?(Array)
        item.deep_flatten
      else
        [item]
      end
    end
  end
end 

[[[1]], [2, 3], [4, 5, [[6]], 7]].deep_flatten
#=> [1, 2, 3, 4, 5, 6, 7]

这有帮助吗?无论如何,这里显示的有用模式是,当您在数组上使用reusion时,通常需要flat_mapeach + concat / push的功能替代。)< / p>

答案 1 :(得分:4)

好吧,如果你知道一点C,你只需要访问文档并单击ruby函数来获取C源代码就可以了。

http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-flatten

对于这种情况,这是一个Ruby实现

def flatten values, level=-1
  flat = []
  values.each do |value|
    if level != 0 && value.kind_of?(Array)
      flat.concat(flatten(value, level-1))
    else
      flat << value
    end
  end
  flat
end

p flatten [1, [2, 3, [4, 5, [6, 7]]]] 
#=> [1, 2, 3, 4, 5, 6, 7] 

答案 2 :(得分:2)

这是一个以尾递归方式书写的扁平的例子。

class Array

  # Monkeypatching the flatten class
  def flatten(new_arr = [])
    self.each do |el|
      if el.is_a?(Array)
        el.flatten(new_arr)
      else
        new_arr << el
      end
    end

    new_arr
  end
end

p flatten [1, [2, 3, [4, 5, [6, 7]]]] 
#=> [1, 2, 3, 4, 5, 6, 7]

虽然看起来ruby并不总是针对尾递归进行优化:Does ruby perform tail call optimization?