检查Ruby数组是否为矩阵的简单方法?

时间:2016-06-17 04:26:34

标签: ruby

我正在研究一个项目,该项目涉及检查输入是否为n维矩阵(并找到其维度),如果没有则会引发错误。例如

arr = [ [[1,2],[3,4]], [[5,6],[7,8]], [[9,10],[11,12]] ]

是维度矩阵[3 2 2]。最简单的通用方法是什么?

5 个答案:

答案 0 :(得分:3)

Ruby实际上有Matrix class,也许可以使用它?

Matrix[[[1,2],[3,4]], [[5,6],[7,8]], [[9,10],[11,12]]]
#=> Matrix[[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]]
Matrix[[1,2], [3]]
# ExceptionForMatrix::ErrDimensionMismatch: row size differs (1 should be 2)

答案 1 :(得分:3)

递归解决方案,但不是很容易理解。

arr1 = [[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]]
arr2 = [[[1, 2], [4]], [6, [7, 8]]]

def dimensions(m)
  if m.any? { |e| e.is_a?(Array) }
    d = m.group_by { |e| e.is_a?(Array) && dimensions(e) }.keys
    [m.size] + d.first if d.size == 1 && d.first
  else
    [m.size]
  end
end

dimensions(arr1)  #=> [3, 2, 2]
dimensions(arr2)  #=> nil

<强>释

算法首先检查嵌套数组m.any? { |e| e.is_a?(Array) }。 如果没有嵌套数组,那么您只有一个维度,并通过[m.size]块中的else返回给定数组的大小。

dimensions([1,2,3])  #=> [3]

如果至少有一个嵌套数组,则必须确保所有元素都是数组,并且数组具有相同的维度。此检查是通过d = m.group_by { |e| e.is_a?(Array) && dimensions(e) }.keys完成的,[[5, 6], [7, 8]].group_by { |e| ... }.keys #=> [[2]], all nested array dimensions are equal [2] [[1, 2], [4]].group_by { |e| ... }.keys #=> [[1], [2]], different dimensions [6, [7, 8]].group_by { |e| ... }.keys #=> [false, [2]], an element isn't an array 按尺寸对所有元素进行分组。

group_by

该算法仅采用if d.size == 1 && d.first[m.size] + d.first的有效结果,并通过nil将嵌套数组的维度添加到结果中。 如果有多个键元素或只有nil这意味着所有嵌套数组都无效,则它会隐式返回python ImportError at /post/5/comment/ cannot import name 'CommentForm' Request Method: GET Request URL: http://localhost:8000/post/5/comment/ Django Version: 1.8 Exception Type: ImportError Exception Value: cannot import name 'CommentForm' Exception Location: E:\pywork\djangogirls\blog\views.py in <module>, line 6 Python Executable: E:\Python35\python.exe Python Version: 3.5.0 Python Path: ['E:\\pywork\\djangogirls', 'E:\\Python35\\lib\\site-packages\\django_debug_toolbar-1.4-py3.5.egg', 'E:\\Python35\\lib\\site-packages\\sqlparse-0.1.19-py3.5.egg', 'E:\\Python35\\python35.zip', 'E:\\Python35\\DLLs', 'E:\\Python35\\lib', 'E:\\Python35', 'E:\\Python35\\lib\\site-packages'] Server time: Thu, 16 Jun 2016 17:02:11 +0800

就是这样。

答案 2 :(得分:2)

查找数据中的模式

如果你看一下

的例子
[[[1,2],[3,4]], [[5,6],[7,8]], [[9,10],[11,12]]]

和维度[3, 2, 2]您可以按以下方式逐个元素地阅读维度:

  1. 包含3个项目的数组,每个项目都是......
  2. 包含2个项目的数组,每个子项目都是......
  3. 包含2个项目的数组。
  4. 这表明可以通过在每个深度级别调用Array#size来计算维度。

    计算维度

    上述方法可以实现为:

    def unchecked_matrix_dimension(matrix)
      dimension = []
      while matrix.is_a?(Array)
        dimension << matrix.size
        matrix = matrix[0]
      end
      dimension
    end
    

    此代码仅查看第一个位置的元素,因此[[1], []]报告的维度为[2, 1],但它根本不是有效矩阵。

    一厢情愿的编码

    假设我们有一个函数matrix_dimension?(matrix, dimension),如果true属于指定的matrix,则返回dimension,否则返回false。我们可以用它来检测这样的无效矩阵:

    def matrix_dimension(matrix)
      dimension = unchecked_matrix_dimension(matrix)
      if matrix_dimension?(matrix, dimension)
        dimension
      else
        nil
      end
    end
    

    事实证明,写matrix_dimension?很容易!

    愿望成真

    我们可以以递归方式定义matrix_dimension?

    1. 如果dimension == [],那么我们期望标量值。
    2. 如果dimension == [d_1],我们预计会有一系列d_1维度为[]的子矩阵(即标量)。
    3. 如果dimension == [d_1, d_2],我们预计会有d_1个维度[d_2]的子矩阵数组(即d_2个标量数组)。
    4. 一般情况下,如果dimension == [d_1, ..., d_n],我们期望一组d_1元素,并且这些元素中的每一个都应该具有维度[d_2, ..., d_n。在Ruby中:

      def matrix_dimension?(matrix, dimension)
        if dimension == []
          !matrix.is_a?(Array)
        else
          matrix.size == dimension[0] &&
            matrix.all? { |submatrix| matrix_dimension?(submatrix, dimension[1..-1]) }
        end
      end
      

      根据matrix_dimension?的定义,如果参数是有效的n维矩阵,则matrix_dimension函数将返回维度,否则返回nil

      完整代码

      def unchecked_matrix_dimension(matrix)
        dimension = []
        while matrix.is_a?(Array)
          dimension << matrix.size
          matrix = matrix[0]
        end
        dimension
      end
      
      def matrix_dimension(matrix)
        dimension = unchecked_matrix_dimension(matrix)
        if matrix_dimension?(matrix, dimension)
          dimension
        else
          nil
        end
      end
      
      def matrix_dimension?(matrix, dimension)
        if dimension == []
          !matrix.is_a?(Array)
        else
          matrix.size == dimension[0] &&
            matrix.all? { |submatrix| matrix_dimension?(submatrix, dimension[1..-1]) }
        end
      end
      

答案 3 :(得分:1)

不使用Matrix类:

input = [ [[1,2],[3,4]], [[5,6],[7,8]], [[9,10],[11,12]] ]
m3 = input.map { |a| a.map(&:size) }
m2 = input.map(&:size)
m1 = input.size

checker = ->(e, memo) { raise unless e == memo; e }

[ m1, m2.reduce(&checker), m3.reduce(&checker).reduce(&checker) ]
#⇒ [3, 2, 2]

答案 4 :(得分:1)

我用递归解决了这个问题。如果数组表示n维矩阵,则返回维数组;否则返回false

<强>代码

def ndim_matrix(arr)
  return false if arr.map(&:size).uniq != [arr.first.size]
  arrays, literals = arr.partition { |e| e.is_a? Array }
  return [arr.size] if arrays.empty?
  return false unless literals.empty?
  res = arr.map { |e| ndim_matrix(e) }.uniq
  return false if res.size > 1 or res == [false]
  [arr.size, *res.first]
end

<强>实施例

arr = [1,2]
ndim_matrix(arr)
  #=> [2]

arr = [ [1,2,3],[4,5,6] ]
ndim_matrix(arr)
  #=> [2,3]

arr = [ [1,2,3],[4,5,6,7] ]
ndim_matrix(arr)
  #=> false

arr = [ [[1,2],[3,4]], [[5,6],[7,8]], [[9,10],[11,12]] ]
ndim_matrix(arr)
  #=> [3,2,2]

arr = [ [[1,2],[3,4]], [[5,6],[7,8]], [[9,10]] ]
ndim_matrix(arr)
  #=> false

arr = [ [[1,2],[3,4]], [[5,6,7],[7,8]], [[9,10],[11,12]] ]
ndim_matrix(arr)
  #=> false

arr = [ [[[1,2,3],[2,1,3]],[[3,4,5],[4,3,2]]],
        [[[5,6,7],[6,5,7]],[[7,8,9],[8,7,6]]],
        [[[9,10,11],[10,9,8]],[[11,12,13],[12,11,10]]] ]
ndim_matrix(arr)
  #=> [3, 2, 2, 3]

arr = [ [[[1,2,3],[2,1,3]],[[3,4],[4,3]]],
        [[[5,6,7],[6,5,7]],[[7,8,9],[8,7,6]]],
        [[[9,10,11],[10,9,8]],[[11,12,13],[12,11,10]]] ]
ndim_matrix(arr)
  #=> false