仅在索引存在时编辑索引

时间:2015-07-07 04:24:47

标签: arrays ruby class multidimensional-array

我需要创建一个0和1的2D网格来表示图像,并创建一个模糊方法,它将1旁边的任何0(左,右,上或下)变为1,如下所示:

0000 => 0000
0000    0010
0010    0111
0000    0010

接下来,我必须允许用户传入一个允许模糊在每个方向上扩展多个空格的数字。如果我调用image.blur(2),它会在每个方向上延伸2个空格,但每个第一步都必须再次调用模糊以考虑对角线。例如:

00000000 => 00010000
00000000    00111000
00010000    01111100
00000000    00111000
00000000    00010000

这是我的代码。

class Image
  attr_accessor :picture
  def initialize(*rows)
    @picture = *rows
  end
  def output_image
    @picture.each_index do |i|
      puts @picture[i].join
    end
  end
  def blur(distance=1)
    @blurred_image = Array.new(@picture.length, 0) {Array.new(@picture[0].length, 0)} #create new array of zeroes the size of @picture
    @picture.each_index do |i|
      @picture[i].each_index do |j|
        if @picture[i][j] == 1
          @blurred_image[i][j]   = 1 if @blurred_image[i][j] 
          @blurred_image[i][j-1] = 1 if @blurred_image[i][j-1] 
          @blurred_image[i][j+1] = 1 if @blurred_image[i][j+1] 
          @blurred_image[i-1][j] = 1 if @blurred_image[i-1][j] 
          @blurred_image[i+1][j] = 1 if @blurred_image[i+1][j] 
        end
      end       
    end
    if distance > 1
      @picture = @blurred_image #save progress of image blur in @picture so we can continue in recursive call 
      blur(distance-1) #iterate as long as distance > 1
      elsif distance == 1 #necessary so blurred image isn't printed 'distance' times
      @blurred_image.each_index do |i|
        puts @blurred_image[i].join
      end
    end
  end
end

pic = Image.new(
  [0,0,0,0,0,0,0,0,0],
  [1,0,0,0,0,0,0,0,0],
  [0,0,0,0,0,0,0,0,0],
  [0,0,0,0,1,0,0,0,0],
  [0,0,0,0,0,0,0,0,0],
  [0,0,0,0,0,0,0,0,0],
  [0,0,0,0,0,0,0,0,0],
  [0,0,0,0,0,0,0,0,0],
  [0,0,0,0,0,0,0,0,0]
)
pic.blur(3)

我的功能有效,但前提是1不超出数组的范围。如果我在角落放置1,看起来我的函数试图编辑不存在的索引的值,并且我收到以下消息:

image_blur.rb:28:in `block (2 levels) in blur': undefined method `[]' for nil:NilClass (NoMethodError)
from image_blur.rb:22:in `each_index'
from image_blur.rb:22:in `block in blur'
from image_blur.rb:21:in `each_index'
from image_blur.rb:21:in `blur'
from image_blur.rb:35:in `blur'
from image_blur.rb:35:in `blur'
from image_blur.rb:47:in `<main>'

如果索引存在,我试图告诉它只为索引分配1。我很感激任何帮助。

3 个答案:

答案 0 :(得分:2)

在您检查一个级别之前,您似乎正在尝试检查两个级别。

例如,picture[1]可能不存在...所以如果您尝试检查picture[i][j]它就会失败。

您可以在索引之前尝试检查每个级别是否存在...

if @picture[i] && @picture[i][j] && @picture[i][j] == 1
   if @blurred_image[i].present?
      @blurred_image[i][j]   = 1 if @blurred_image[i][j] 
      @blurred_image[i][j-1] = 1 if @blurred_image[i][j-1] 
      @blurred_image[i][j+1] = 1 if @blurred_image[i][j+1]
   end
   @blurred_image[i-1][j] = 1 if @blurred_image[i-1] && @blurred_image[i-1][j] 
   @blurred_image[i+1][j] = 1 if @blurred_image[i+1] && @blurred_image[i+1][j] 

答案 1 :(得分:1)

我的第一个想法是放弃这样的基于查找的解决方案:

adjacents = [[-1, 0], [0, -1], [0, 0], [1, 0], [0, 1]].freeze
@blurred_image = Array.new(@picture.length, 0) { Array.new(@picture[0].length, 0) }

@picture.each_index do |i|
  @picture[i].each_index do |j|
    if @picture[i][j] == 1
      adjacents.each { |x, y| (a = @blurred_image[i+x]) && a[j+y] &&= 1 }
    end
  end
end

注意&&=运算符只有在左侧是真实的情况下才会执行赋值。因此,如果您使用nil值初始化内部数组,则会失败。

答案 2 :(得分:0)

感谢帮助。我昨晚看到了这个问题的另一个答案,但我认为海报因某种原因删除了它?无论如何,我做了他们推荐的事情,这是为了使我的blur_image指数大于图像本身 - 基本上每个方向都有一个额外的行/列。然后,当我向图像添加1时,我只是相应地调整了我的位置,以便图像仍然居中,然后我会在每次迭代结束时删除额外的行和列。我也可以尝试其他这些方法,但这种方式对我很有用。

def blur(distance=1)
    #create new array of zeroes with 1 layer of extra 'padding', so any edges can push outwards without getting a nil error
    @blurred_image = Array.new(@picture.length+2, 0) {Array.new(@picture[0].length+2, 0)} 

    @picture.each_index do |i|
        @picture[i].each_index do |j|
            if @picture[i][j] == 1
                @blurred_image[i+1][j+1] = 1 
                @blurred_image[i+1][j]   = 1 
                @blurred_image[i+1][j+2] = 1 
                @blurred_image[i][j+1]   = 1 
                @blurred_image[i+2][j+1] = 1  
            end
        end     
    end

    #remove padding after checking and editing array to make it original size
    @blurred_image.pop
    @blurred_image.shift
    @blurred_image.each_index do |i|
        @blurred_image[i].pop
        @blurred_image[i].shift
    end

    if distance > 1
        @picture = @blurred_image #save progress of image blur in @picture so we can continue in recursive call 
        blur(distance-1) #iterate as long as distance > 1
    elsif distance == 1 #necessary so blurred image isn't printed 'distance' times
        @blurred_image.each_index do |i|
            puts @blurred_image[i].join
        end 
    end
end