2维数组转换

时间:2016-12-17 02:04:00

标签: arrays ruby

这是我的阵列:

[[0,0,0,0],
  [0,1,0,0],
  [0,0,0,1],
  [0,0,0,0]]

我希望“1”的上方,下方,右侧和左侧的“0”单元格也可以变为1。

预期输出为:

0100
1111
0111
0001

然而,我的代码:

class Image
  def initialize(image)
    @image = image
  end

  def output_image
    @image.map do |image|
      puts image.join('')
    end
  end

  def blur
    find_ones.each do |x, y|
      blur_cell x, y
    end
  end

  def find_ones
    ones = []
    @image.each_with_index do |row, y|
      row.each_with_index do |cell, x|
        ones << [x, y] if cell == 1
      end
    end
    ones
  end

  def blur_cell(x, y)
    write_cell x + 1, y, 1
    write_cell x - 1, y, 1
    write_cell x, y + 1, 1
    write_cell x, y - 1, 1
  end

  def write_cell(x, y, value)
    return nil unless y > 0 && y < @image.length
    return nil unless x > 0 && x < @image[0].length
    @image[y][x] = value
  end
end

image = Image.new([
  [0, 0, 0, 0],
  [0, 1, 0, 0],
  [0, 0, 0, 1],
  [0, 0, 0, 0]
])

image.blur
image.output_image

我收到了这个输出:

0000
0111
0111
0001

任何帮助指出我的错误在哪里或任何有关如何解决它的建议将不胜感激:)

2 个答案:

答案 0 :(得分:2)

您的代码中的错误

您的代码有一些小错误。以下是更正后的代码。将它与原始代码逐行​​进行比较,您将看到错误以及我如何修复它们。我也做了一些简化。

class Image
  def initialize(image)
    @image = image
  end

  def output_image
    @image.map do |image|
      puts image.join('')
    end
  end

 def blur
    find_ones.each do |x, y|
      blur_cell x, y
    end
  end

  def find_ones
    ones = []
    @image.each_with_index do |row, x|
      row.each_with_index do |cell, y|
        ones << [x, y] if cell == 1
      end
    end
    ones
  end

  def blur_cell(x, y)
    write_cell x + 1, y
    write_cell x - 1, y
    write_cell x, y + 1
    write_cell x, y - 1
  end

  def write_cell(x, y)
    return unless y >= 0 && y < @image.length
    return unless x >= 0 && x < @image[0].length
    @image[x][y] = 1  # was reversed
  end
end

image = Image.new([
  [0, 0, 0, 0],
  [0, 1, 0, 0],
  [0, 0, 0, 1],
  [0, 0, 0, 0]
])

image.blur
image.output_image
  #=> 0100
  #   1111
  #   0111
  #   0001

建议的替代方案

这是另一种方法。

def convert(arr)
  return [] if arr.empty?
  nbr_rows = arr.size
  nbr_cols = arr.first.size
  a = container(arr)
  (1..nbr_rows).
    each_with_object(Array.new(nbr_rows) { Array.new(nbr_cols) }) { |i,b|
      (1..nbr_cols).each { |j|
        b[i-1][j-1] = [a[i][j], a[i][j-1], a[i][j+1], a[i-1][j], a[i+1][j]].max } }
end

def container(arr)
  nbr_rows = arr.size
  nbr_cols = arr.first.size
  Array.new(nbr_rows+2) { |i|
    Array.new(nbr_cols+2) { |j| (i.zero? || i==nbr_rows+1 || j.zero? ||
      j==nbr_cols+1) ? 0 : arr[i-1][j-1] } }
end

示例

arr = [
  [0, 0, 0, 0],
  [0, 1, 0, 0],
  [0, 0, 0, 1],
  [0, 0, 0, 0]
]

convert arr
  #=> [[0, 1, 0, 0],
  #    [1, 1, 1, 1],
  #    [0, 1, 1, 1],
  #    [0, 0, 0, 1]]

<强>解释

首先观察如果上,下,左或右的元素等于1,则将等于0的元素设置为1.对于不在第一行或最后一行或第一列或最后一列中的元素,计算很简单。处理周边元素的一种方法是构造第二个数组,该数组以原始数组开始,并在前后添加零行,并在左右添加零行。然后对除周边行和列之外的所有元素进行计算。最后,第一行和最后一行以及第一列和最后一列被剥离。这就是我所做的,

示例中使用的数组的步骤如下。首先考虑方法container

nbr_rows = arr.size
  #=> 4 
nbr_cols = arr.first.size
  #=> 4 
Array.new(nbr_rows+2) { |i|
  Array.new(nbr_cols+2) { |j| (i.zero? || i==nbr_rows+1 || j.zero? ||
    j==nbr_cols+1) ? 0 : arr[i-1][j-1] } }
  #=> Array.new(6) { |i|
  #     Array.new(6) { |j| (i.zero? || i==5 || j.zero? ||
  #       j==5) ? 0 : arr[i-1][j-1] } }
  #=> [[0, 0, 0, 0, 0, 0],
  #    [0, 0, 0, 0, 0, 0],
  #    [0, 0, 1, 0, 0, 0],
  #    [0, 0, 0, 0, 1, 0],
  #    [0, 0, 0, 0, 0, 0],
  #    [0, 0, 0, 0, 0, 0]] 

请注意,此数组arr夹在两行零和两列零之间。

现在让我们逐步完成convert

arr.empty?
  #=> false, so we do not return []
nbr_rows = arr.size
  #=> 4 
nbr_cols = arr.first.size
  #=> 4 
a = container(arr)
  #=> [[0, 0, 0, 0, 0, 0],
  #    [0, 0, 0, 0, 0, 0],
  #    [0, 0, 1, 0, 0, 0],
  #    [0, 0, 0, 0, 1, 0],
  #    [0, 0, 0, 0, 0, 0],
  #    [0, 0, 0, 0, 0, 0]]     
(1..nbr_rows).each_with_object(Array.new(nbr_rows) { Array.new(nbr_cols) }) { |i,b|
  (1..nbr_cols).each { |j|
    b[i-1][j-1] = [a[i][j], a[i][j-1], a[i][j+1], a[i-1][j], a[i+1][j]].max } }
  #=> (1..4).each_with_object(Array.new(4) { [0,0,0,0] }) { |i,b|
  #     (1..4).each { |j|
  #       b[i-1][j-1] = [a[i][j], a[i][j-1], a[i][j+1], a[i-1][j], a[i+1][j]].max } }
  #=> [[0, 1, 0, 0],
  #    [1, 1, 1, 1],
  #    [0, 1, 1, 1],
  #    [0, 0, 0, 1]]

对于不熟悉Enumerable#each_with_object的读者,最后一个表达式实际上与以下三行相同。

b = Array.new(nbr_rows) { Array.new(nbr_cols) }
(1..nbr_rows).each { |i|
  (1..nbr_cols).each { |j|
    b[i-1][j-1] = [a[i][j], a[i][j-1], a[i][j+1], a[i-1][j], a[i+1][j]].max } }
b

答案 1 :(得分:1)

对于Ruby解决方案,请参阅@ CarySwoveland的答案。

由于您的课程名为blur_cell且您的方法名称为convert matrix.png -morphology Dilate Diamond dilated_matrix.png ,因此您可能需要检查Image MagickMiniMagick

您正在寻找的转化称为"diamond dilation"

使用ImageMagick,它很简单:

.pbm

转换

matrix.png

dilated_matrix.png

要将矩阵转换为位图,反之亦然,您可以使用 这个gem可以读取和写入{{1}}个文件。