我正在编写一个脚本,它带有两个参数,一个二维数组(全0和1' s)和一个最大垂直距离n,并返回一个修改过的数组。这样,如果n = 3,则以下数组
[[0,0,0,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,1,0,0,0],
[0,0,1,1,1,0,0],
[0,1,1,1,1,1,0],
[1,1,1,1,1,1,1],
[0,1,1,1,1,1,0],
[0,0,1,1,1,0,0],
[0,0,0,1,0,0,0]]
(数组输入可以有任何矩形尺寸;任何元素都可以是10)。
我的想法是克隆原始数组,扫描1年,然后将更改映射到克隆中。我试图将更改首先映射到右侧,然后映射到原始1的左侧。
我得到了以下工作,它改变了数组的中心列:
a = [[0,0,0,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]]
cloned = a.map(&:clone)
n = 3
a.each.with_index do |whole_row, row|
whole_row.each.with_index do |cell, column|
if cell == 1
#center column
row_path = row - n
(n*2+1).times do
unless (cloned[row_path][column]).nil?
cloned[row_path][column] = 1
end
row_path += 1
end
end
end
end
cloned
然而,当我尝试向右移动此过程时,我得到了undefined method '[]' for nil:NilClass
。我在哪里弄乱这里的逻辑?
a = [[0,0,0,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]]
cloned = a.map(&:clone)
n = 3
a.each.with_index do |whole_row, row|
whole_row.each.with_index do |cell, column|
if cell == 1
#central column & right side
row_path = row - n
column_path = column
repetition = 2 * n + 1
(n+1).times do
(repetition).times do
unless cloned[row_path][column_path].nil?
cloned[row_path][column_path] = 1
end
row_path += 1
end
repetition -= 2
column_path += 1
row_path += 1
end
end
end
end
cloned
(我的想法是在原始数组的右边和左边两次实现这个过程。)
答案 0 :(得分:1)
发生错误是因为您尝试访问不存在的数组索引的子数组中的项。
此行 - cloned[row_path][column_path].nil?
此处row_path
在某些迭代中不包含任何值,这是因为您将它递增两次。
从(repetition).times
删除增量应修复它。
希望这有帮助
答案 1 :(得分:1)
从您的示例中我假设[i,j]
和[k,l]
之间的元素之间的“垂直距离”由方法给出:
def dist((i,j),(k,l))
(i-k).abs + (j-l).abs
end
在这种情况下,“矩形距离”将是更好的描述符。如果这个假设不正确,你不需要再读了。
对于你的例子:
a = [[0,0,0,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]]
n = 3
在定义上面的方法dist
之后,您可以按如下方式构造所需的数组:
nrows = a.size
#=> 7
ncols = a.first.size
#=> 7
Array.new(nrows) do |i|
Array.new(ncols) do |j|
nrows.times.any? do |k|
ncols.times.any? do |l|
a[k][l] == 1 && dist([i,j],[k,l]) <= n
end
end ? 1 : 0
end
end
#=> [[0, 0, 0, 1, 0, 0, 0],
# [0, 0, 1, 1, 1, 0, 0],
# [0, 1, 1, 1, 1, 1, 0],
# [1, 1, 1, 1, 1, 1, 1],
# [0, 1, 1, 1, 1, 1, 0],
# [0, 0, 1, 1, 1, 0, 0],
# [0, 0, 0, 1, 0, 0, 0]]
或者,你可以反过来做(计算nrows
和ncols
)。
b = Array.new(nrows) { Array.new(ncols,0) }
nrows.times.each do |i|
ncols.times.each do |j|
next unless a[i][j]==1
nrows.times.each do |k|
ncols.times.each do |l|
b[k][l] = 1 if dist([i,j],[k,l]) <= n
end
end
end
end
b
通过限制检查的行(作为目标行和n
的函数),以及对于考虑的每一行,通过限制检查的列(作为函数),可以使这两种方法更有效行,目标行和列以及n
)。
答案 2 :(得分:0)
考虑到Dwijen的回答,我调整了脚本,以便在测试时索引内部没有任何内容。我收到错误,直到我继续unless (row_path > cloned.length - 1 )
这通过了测试:
a.each.with_index do |whole_row, row|
whole_row.each.with_index do |cell, column|
if cell == 1
#central column & right side
row_path = row - n
column_path = column
repetition = 2 * n + 1
counter = 0
(n+1).times do
(repetition).times do
unless (row_path > cloned.length - 1 ) || cloned[row_path][column_path].nil?
cloned[row_path][column_path] = 1
end
row_path += 1
end
counter += 1
repetition -= 2
column_path += 1
row_path = row - n + counter
end
#central column & left side
row_path = row - n
column_path = column
repetition = 2 * n + 1
counter = 0
(n+1).times do
(repetition).times do
unless (row_path > cloned.length - 1 ) || cloned[row_path][column_path].nil?
cloned[row_path][column_path] = 1
end
row_path += 1
end
counter -= 1
repetition -= 2
column_path -= 1
row_path = row - n - counter
end
end
end
end