如何检测递归数组和散列?

时间:2014-04-11 02:16:30

标签: ruby arrays recursion hash

如何检测包含下面的abc等递归结构的数组或哈希?

  • 递归数组的最简单实例

    a = []
    a[0] = a
    a # => [[...]]
    
  • 递归周期/深度不是一个

    b = [[], :foo]
    b[0][0] = b
    b # => [[[...]], :foo]
    
  • 非根级别的递归

    c = [a, :foo]
    c # => [[...], :foo]
    

3 个答案:

答案 0 :(得分:4)

我喜欢递归。

这是一个不错的方式,迭代所有内容并保持你看到的对象的哈希值(用于快速查找)

class Object
  def is_recursive?(known = {})
    false
  end
end

module Enumerable
  def is_recursive?(known = {})
    return true if known.include?(self)
    known[self] = true
    begin
      any? do |*args|
        args.any?{|item| item.is_recursive?(known)}
      end
    ensure
      known[self] = false
    end
  end
end

x = []; x << x
p x.is_recursive? # => true
p ({x => 42}).is_recursive? # => true
p [{foo: x}].is_recursive? # => true
p [[[[[[:foo], {bar: [42]}]]]]].is_recursive? # => false

请注意,这有点粗糙,你可能遇到麻烦。例如,你有[1..Float::INFINITY].is_recursive?的无限循环,虽然这很容易用

来解决
class Range
  def is_recursive?(known = {})
    false # optimization
  end
end

答案 1 :(得分:3)

您无法展平递归数组,因此可以通过以下方式检查:

begin
  a.flatten
rescue ArgumentError => e
  e.to_s =~ /recursive/
end

答案 2 :(得分:1)

您正在寻找方法include?

a = []
a[0] = a
a.include? a
 => true 

但这不适用于嵌套数组,作为第二个例子。你可以递归地做到这一点:

def check_recursive(array, target = nil)
  target ||= array
  return true if array.include?(target)
  array.any? do |obj|
    if obj.kind_of? Array
      check_recursive(obj, target)
      obj.include?(target)
    end
  end
end

基本上有两种算法可以递归:查看深度或deep-first searchbreadth-first search。最佳解决方案取决于您的问题。我的例子实现了深度搜索,这通常是一个好主意。