我是初学者,正在做一些练习。我正在尝试操纵一个二维数组,这样如果一个元素是1,那么周围的非对角元素应该改为1:
[[0,0,0,0],
[0,0,1,0],
[0,0,0,0],
[0,0,0,0]]
应该返回
[[0,0,1,0],
[0,1,1,1],
[0,0,1,0],
[0,0,0,0]]
我使用嵌套的each_with_index遇到问题:在我调整左右周围的初始更改后,随着方法的迭代,它会通过之前的调整进行调整并进行不必要的更改。此外,应该更改“底部”元素的行会引发错误:
a = [[0,0,0,0],
[0,0,1,0],
[0,0,0,0],
[0,0,0,0]
]
a.each_with_index do |m, n| # n == index of main array
m.each_with_index do |x, y| # y == index of subarray
if x == 1
a[n][y+1] = 1 unless (a[n][y+1]).nil? #right
a[n][y-1] = 1 unless (a[n][y-1]).nil? #left
a[n-1][y] = 1 unless (a[n-1][y]).nil? #top
a[n+1][y] = 1 unless (a[n+1][y]).nil? #bottom--currently giving an error
end
end
end
关于如何解决这两个方面的任何建议都会受到欢迎。
答案 0 :(得分:3)
为了避免上一步的干扰,您可以(深)复制数组并将引用数组与修改数组分开,或者在修改数组之前提取所有相关索引。后者更好。此外,使用平面数组比处理嵌套数组容易得多,因此我将a
转换为平展数组b
,并在b
内工作。
b = a.flatten
b
.each_index.select{|i| b[i] == 1}
.each do
|i|
b[i - 1] = 1 if b[i - 1] and i - 1 >= 0
b[i + 1] = 1 if b[i + 1]
b[i - 4] = 1 if b[i - 4] and i - 4 >= 0
b[i + 4] = 1 if b[i + 4]
end
a = b.each_slice(4).to_a
# => [[0, 0, 1, 0], [0, 1, 1, 1], [0, 0, 1, 0], [0, 0, 0, 0]]
答案 1 :(得分:1)
我建议您使用Matrix类。
require 'matrix'
m = Matrix[*a]
#=> Matrix[[0, 0, 0, 0],
# [0, 0, 1, 0],
# [0, 0, 0, 0],
# [0, 0, 0, 0]]
row, col = m.index(1)
#=> [1, 2]
Matrix.build(m.row_size, m.column_size) { |r,c|
(c-col).abs + (r-row).abs <= 1 ? 1 : 0 }.to_a
#=> [[0, 0, 1, 0],
# [0, 1, 1, 1],
# [0, 0, 1, 0],
# [0, 0, 0, 0]]
此非矩阵版本(使用方法Array#index,Fixnum#divmod,Array::new,Enumerable#each_slice以及其他一些方法)如下所示。
nrows, ncols = a.size, a.first.size
#=> [4, 4]
row, col = a.flatten.index(1).divmod(ncols)
#=> [1, 2]
Array.new(nrows*ncols) do |i|
r, c = i.divmod(ncols)
(c-col).abs + (r-row).abs <= 1 ? 1 : 0
end.each_slice(ncols).to_a
#=> [[0, 0, 1, 0],
# [0, 1, 1, 1],
# [0, 0, 1, 0],
# [0, 0, 0, 0]]
我发现使用Matrix
类的方法更容易理解,但可能效率不高。