Arrays 如何使用Ruby计算2D数组中的数字或矩形?

Arrays 如何使用Ruby计算2D数组中的数字或矩形?,arrays,ruby,image,multidimensional-array,Arrays,Ruby,Image,Multidimensional Array,假设我有一个数组。我想确定一个左上角和右下角的矩形点。使用单个矩形很容易。请参阅下面我的实现。 当有多个矩形时,问题变得具有挑战性。如何用多个矩形识别左上角和右下角点 连续规则0是矩形:在下面的示例中有3个矩形。 我的理解是,当一个包含n元素(“行”)的给定数组,每个元素都是m元素(“列”)的数组,被视为一个矩阵时,构建一个只包含零的所有子矩阵的数组,其中每个子矩阵由其左上和右下元素的坐标标识。例如,元素数组[1][4],数组[1][5],数组[2][4]和数组[2][5],它们都等于零,由一对

假设我有一个数组。我想确定一个左上角和右下角的矩形点。使用单个矩形很容易。请参阅下面我的实现。 当有多个矩形时,问题变得具有挑战性。如何用多个矩形识别左上角和右下角点

连续规则0是矩形:在下面的示例中有3个矩形。
我的理解是,当一个包含
n
元素(“行”)的给定数组,每个元素都是
m
元素(“列”)的数组,被视为一个矩阵时,构建一个只包含零的所有子矩阵的数组,其中每个子矩阵由其左上和右下元素的坐标标识。例如,元素
数组[1][4]
数组[1][5]
数组[2][4]
数组[2][5]
,它们都等于零,由一对坐标
[[1,4],[2,5]
标识的子矩阵组成

require 'matrix'

def all_zero_subarrays(arr)
  m = Matrix[*arr]
  last_row, last_col = arr.size-1, arr.first.size-1
  (0..last_row).each_with_object([]) do |i,a|
    (0..last_col).each do |j|
      next unless arr[i][j].zero?
      (i..last_row).each do |ii|
        (j..last_col).each do |jj|
          next unless arr[ii][jj].zero?
          a << [[i,j], [ii,jj]] if m.minor((i..ii), (j..jj)).to_a.flatten.uniq == [0]
        end
      end
    end
  end
end

array = [
  [1,1,1,1,0,0],
  [1,0,1,1,0,0],
  [1,0,1,1,0,0],
  [1,1,0,0,1,1],
  [1,1,0,1,1,1]]
见和

如果需要,可以删除表示“包含”在另一个子矩阵中的子矩阵的
arr
元素。例如,
[[0,4],[1,5]]
包含在
[[0,4],[2,5]]

def second_rect_in_first?(rect1, rect2)
  ul1, br1 = rect1
  ul2, br2 = rect2
  first_ul_of_second?(ul1, ul2) && first_ul_of_second?(br2, br1)
end

def first_ul_of_second?((i1, j1), (i2, j2))
  (i1 <= i2) && (j1 <= j2)
end

arr.each_with_object([]) do |rect, a|
  next if a.any? { |arect| second_rect_in_first?(arect, rect) } 
  a.reject! { |arect| second_rect_in_first?(rect, arect) } 
  a << rect  
end
  #=> [[[0, 4], [2, 5]],
  #    [[1, 1], [2, 1]],
  #    [[3, 2], [3, 3]],
  #    [[3, 2], [4, 2]]]  
def second\u rect\u in_first?(rect1,rect2)
ul1,br1=rect1
ul2,br2=rect2
第二个的第一个(ul1,ul2)和第二个的第一个(br2,br1)
结束
def first_ul_of_second?(i1,j1)、(i2,j2))

(i1我的理解是,当一个给定数组包含
n个
元素(“行”)时,每个元素都是
m
元素(“列”)的数组被视为一个矩阵,构造一个只包含零的所有子矩阵的数组,其中每个子矩阵由其左上和右下元素的坐标标识。例如,元素
数组[1][4]
数组[1][5]
数组[2][4]
数组[2][5]
,都等于零,由一对坐标确定的子矩阵组成
[[1,4],[2,5]]

require 'matrix'

def all_zero_subarrays(arr)
  m = Matrix[*arr]
  last_row, last_col = arr.size-1, arr.first.size-1
  (0..last_row).each_with_object([]) do |i,a|
    (0..last_col).each do |j|
      next unless arr[i][j].zero?
      (i..last_row).each do |ii|
        (j..last_col).each do |jj|
          next unless arr[ii][jj].zero?
          a << [[i,j], [ii,jj]] if m.minor((i..ii), (j..jj)).to_a.flatten.uniq == [0]
        end
      end
    end
  end
end

array = [
  [1,1,1,1,0,0],
  [1,0,1,1,0,0],
  [1,0,1,1,0,0],
  [1,1,0,0,1,1],
  [1,1,0,1,1,1]]
见和

如果需要,可以删除表示另一个子矩阵中“包含”的子矩阵的
arr
元素。例如,
[[0,4],[1,5]
包含在
[[0,4],[2,5]]
中。下面是一种方法

def second_rect_in_first?(rect1, rect2)
  ul1, br1 = rect1
  ul2, br2 = rect2
  first_ul_of_second?(ul1, ul2) && first_ul_of_second?(br2, br1)
end

def first_ul_of_second?((i1, j1), (i2, j2))
  (i1 <= i2) && (j1 <= j2)
end

arr.each_with_object([]) do |rect, a|
  next if a.any? { |arect| second_rect_in_first?(arect, rect) } 
  a.reject! { |arect| second_rect_in_first?(rect, arect) } 
  a << rect  
end
  #=> [[[0, 4], [2, 5]],
  #    [[1, 1], [2, 1]],
  #    [[3, 2], [3, 3]],
  #    [[3, 2], [4, 2]]]  
def second\u rect\u in_first?(rect1,rect2)
ul1,br1=rect1
ul2,br2=rect2
第二个的第一个(ul1,ul2)和第二个的第一个(br2,br1)
结束
def first_ul_of_second?(i1,j1)、(i2,j2))
(i1基本思想:

  • 深度克隆阵列,这样我们就不会把它搞砸
  • 找到矩形的左上角
  • 看看它有多高
  • 看看它有多宽
  • 把它填满,这样我们就再也找不到那些地方了
  • 重复此操作,直到没有剩余的零
所以

class RectFinder
基本思想:

  • 深度克隆阵列,这样我们就不会把它搞砸
  • 找到矩形的左上角
  • 看看它有多高
  • 看看它有多宽
  • 把它填满,这样我们就再也找不到那些地方了
  • 重复此操作,直到没有剩余的零
所以

class RectFinder
例如,
parse_array(array)#=>[[0,4]、[0,5]、[1,1]、[1,5]、[2,1]、[2,4]、[2,5]、[3,2]、[3,3]、[4,2]、[4,3]]
。请解释这意味着什么,并澄清“连续的0是矩形”。请通过编辑答案而不是在注释中进行编辑。(并非所有读者都能阅读所有注释。)我更新了这个问题,很抱歉我工作太忙了!上面的例子有3个矩形组。第一组是[[0,4],[2,5];第二组是[[1,1],[2,1];最后一组是[[3,2],[4,3]。其中[[左上],[右下]]是如何编码的信息当
数组=[[0,0],[0,1]]时,期望的结果是什么
?例如,
parse_array(array)#=>[[0,4]、[0,5]、[1,1]、[1,5]、[2,1]、[2,4]、[2,5]、[3,2]、[3,3]、[4,2]、[4,3]
。请解释这意味着什么,并澄清“连续的0是矩形”。请通过编辑答案而不是在注释中进行编辑。(并非所有读者都能阅读所有注释。)我更新了这个问题,很抱歉我工作太忙了!上面的例子有3个矩形组。第一组是[[0,4],[2,5];第二组是[[1,1],[2,1];最后一组是[[3,2],[4,3]。其中[[左上],[右下]]是如何编码的信息当
数组=[[0,0],[0,1]]时,期望的结果是什么
?我修改了答案以提供所需信息。我修改了答案以提供所需信息。干得好!我们的假设之间有一点不同。如果
数组=[[0,0,0],[0,1,1],[0,1,1],[0,1,1]]
,则返回
[[0,0],[0,2],[[1,0],[3,0]]
,它给出了一个行偏差,而我返回
[[0,0],[0,2]],[[0,0],[3,0]]
,重叠
[0,0]
。干得好!我们的假设之间有一点不同。如果
数组=[[0,0,0],[0,1,1],[0,1,1],[0,1]
,你返回
[[0,0,0,2],[1,0],[3,0]]
,它给出一个行偏差,而我返回
[[0,0],[0,2]],[[0,0],[3,0]]]
,它们重叠
[0,0]
class RectFinder < Array
  def initialize(array)
    super()
    @a = array.map { |x| x.dup }
    @h = array.size
    @w = array.first.size
    find_rects
  end

  private def find_rects
    (0...@h).each do |r|
      (0...@w).each do |c|
        if @a[r][c] == 0
          self << find_rect(r, c)
        end
      end
    end
  end

  private def find_rect(r, c)
    w = ((c + 1)...@w).take_while { |cc| @a[r][cc] == 0 }.size + 1
    h = ((r + 1)...@h).take_while { |rr| (c...(c + w)).all? { |cc| @a[rr][cc] == 0 } }.size + 1
    (r...(r + h)).each { |rr| @a[rr][c...(c + w)] = [1] * w }
    [[r, c], [r + h - 1, c + w - 1]]
  end
end

p RectFinder.new(array)
# => [[[0, 4], [2, 5]], [[1, 1], [2, 1]], [[3, 2], [4, 3]]]