Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 如何检测递归数组和哈希?_Ruby_Arrays_Recursion_Hash - Fatal编程技术网

Ruby 如何检测递归数组和哈希?

Ruby 如何检测递归数组和哈希?,ruby,arrays,recursion,hash,Ruby,Arrays,Recursion,Hash,如何检测包含递归结构(如下面的a、b和c)的数组或散列 递归数组的最简单实例 a = [] a[0] = a a # => [[...]] 递归周期/深度不是一个 b = [[], :foo] b[0][0] = b b # => [[[...]], :foo] 非根级别的递归 c = [a, :foo] c # => [[...], :foo] 不能展平递归数组,因此可以通过以下方式进行检查: begin a.flatten rescue ArgumentE

如何检测包含递归结构(如下面的
a
b
c
)的数组或散列

  • 递归数组的最简单实例

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

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

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

不能展平递归数组,因此可以通过以下方式进行检查:

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

您正在寻找方法
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
基本上有两种中止可以发现它是递归的:深入查找或。最好的解决方案取决于你的问题。我的示例实现了深度优先搜索,这通常是个好主意。

我喜欢递归

这里有一个不错的方法,遍历所有内容并保留所看到对象的散列(用于快速查找)


伟大的该错误看起来像一个错误。那么,递归数组是否是引发ArgumentError的唯一原因?@sawa我不确定,所以最好只捕捉ArgumentError。@sawa:引发了错误。引发
ArgumentError
的唯一其他方法是,如果任何元素定义了一个
到_ari
,它会以某种方式引发它。@xdazz您的答案很好,但Marc AndréLafortune给出了一个更一般的答案,因此我正在移动验收检查。感谢您的帮助。这很好,但是当递归不在根级别时,它会引发stackoverflow错误<代码>检查递归([a,:bar])#=>stackoverflow。感谢您涵盖所有案例。那些加拿大人真聪明!
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
class Range
  def is_recursive?(known = {})
    false # optimization
  end
end