如何检测包含下面的a
,b
和c
等递归结构的数组或哈希?
递归数组的最简单实例
a = []
a[0] = a
a # => [[...]]
递归周期/深度不是一个
b = [[], :foo]
b[0][0] = b
b # => [[[...]], :foo]
非根级别的递归
c = [a, :foo]
c # => [[...], :foo]
答案 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 search或breadth-first search。最佳解决方案取决于您的问题。我的例子实现了深度搜索,这通常是一个好主意。