在Ruby中获取多维数组的维度

6
我刚开始学习 Ruby。 现在我需要弄清楚多维数组的维数。我查看了 Ruby 文档中的所有数组方法,但找不到返回维数的方法。
这是一个示例: [[1, 2],[3,4],[5,6]] 的维数应该是 2。 [[[1,2],[2,3]],[[3,4],[5]]] 的维数应该是 3。
6个回答

6
简单,面向对象的解决方案。
class Array
  def depth
    map {|element| element.depth + 1 }.max
  end
end

class Object
  def depth
    0
  end
end

3

由于Ruby的数组可以包含任何东西,包括哈希或其他数组,因此没有内置函数可以解决“维度”的定义问题。所以我认为你需要自己实现这个功能。

如果您的“维度”指的是“最深嵌套级别的数组”,那么可以使用以下代码:

def get_dimension a
  return 0 if a.class != Array
  result = 1
  a.each do |sub_a|
    if sub_a.class == Array
      dim = get_dimension(sub_a)
      result = dim + 1 if dim + 1 > result
    end
  end
  return result
end

编辑:由于Ruby是一种强大的语言,可以让你做一些花哨的事情,因此您还可以将get_dimension方法作为Array的方法实现:
 class Array
   def get_dimension
   ... # code from above slightly modified
   end
 end

1
在最简单的情况下
depth = Proc.new do |array|
  depth = 1
  while Array === array.first do
    array = array.first
    depth += 1
  end
  depth
end

array =  [[[1,2],[2,3]],[[3,4],[5]]]    
depth.call(array)
#=> 3

或者这个小递归方法

def depth(array, depth=1)
  array = array.send(:first)
  Array === array ? depth(array, depth+1) : depth
end

array =  [[[1,2],[2,3]],[[3,4],[5]]]    
depth(array)
#=> 3

为什么要使用存储过程,而不是普通的函数? - Sergio Tulentsev
我不确定,文档 %) 这是行为驱动的东西。我在控制台中,通常使用控制台中的procs。当然,它可以重写为一个普通的方法。 - fl00r
我只是好奇,仅此而已 :) - Sergio Tulentsev
2
我认为在这种情况下这个方法不会起作用: a = [1,[2,3]]。你的函数输出将是1,而实际上我相信我们想要得到的是2。 - Ivaylo Strandjev
我相信他在谈论“矩阵”。 - fl00r
@fl00r 他的第二个例子不是矩阵。 - Ivaylo Strandjev

0

这样怎么样:

class Object
    def dimension
        self.class == Array ? 1 + self[0].dimension : 0
    end
end
[[[1,2],[2,3]],[[3,4],[5]]].dimension
#=> 3

1
再次强调,当a = [3,[1,2]]时,这种方法将无法正常工作。输出将是1而不是2。但稍加修改即可使其适用于该情况。 - Ivaylo Strandjev
@izomorphius - 在我看来,在那种情况下,1是正确的值。不过你说得对,问题并没有表述清楚。 - pguardiario

0

我对其他解决方案不满意,所以我写了一个我实际会使用的一行代码:

def depth(array)
  array.to_a == array.flatten(1) ? 1 : depth(array.flatten(1)) + 1
end

它将逐层压缩数组,直到无法再压缩为止,同时计算维度。

为什么这样更好呢?

  • 不需要修改本地类(尽可能避免)
  • 不使用元编程(is_a?sendrespond_to?等)
  • 相当容易阅读
  • 也适用于哈希表(注意array.to_a
  • 实际上有效(不像只检查第一个分支和其他愚蠢的东西)

0
作为 Tass 方法的修改:
class Array
    def depth
        map{ |element| element.is_a?( Vector ) ? element.depth + 1 : 1 }.max 
    end
end

depth作为Array的方法保留,不需要向Object添加方法。

当然,如果您要调用my_object.depth,并且事先不知道my_object.class == Array,那么这可能是您想要的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接