如何将数组中的 nil 转换为 0 以获得总和?

How do I convert nil to 0 in an array to get the sum?

使用二维数组制作康威生命游戏的一个版本,并且在尝试计算每个单元格 "neighbors" 的总和时,我一直被 nil 值阻止。

  def neighbor_count
      grid.each_with_index do |row, idx|
          row.each_with_index do |column, idx2|
              [grid[idx - 1][idx2 - 1], grid[idx - 1][idx2], grid[idx - 1][idx2 + 1],
              grid[idx][idx2 - 1], grid[idx][idx2], grid[idx][idx2 + 1],
              grid[idx + 1][idx2 - 1], grid[idx + 1][idx2], grid[idx + 1][idx2 + 1]
              ].compact.sum

          end
      end
  end
如果在数组前面包含 "puts",

.compact 似乎会产生最多的结果,但我尝试过的 none 选项给我 100%。我试过 reduce(:+)、inject、.to_i、reject(去除 nil 值)等等。

这里缺少什么?

错误:world.rb:35:in block (2 levels) in neighbor_count': undefined method[]' for nil:NilClass (NoMethodError)

第 35 行是上面的行。compact.sum

零值只是疾病的症状。不要治疗症状,摆脱问题!那是你违反了数组边界。

.each_with_index 枚举从第一个到最后一个的所有索引。因此,最后一个索引上的 idx + 1 将触发这种越界情况。而第一个 idx - 1 将产生意外值而不是错误,这将影响您的计算。祝你调试顺利。 :)

在您的代码中进行一些保护检查,以确保您永远不会越界。


绝对清楚,问题不在于 grid[idx + 1][idx2] 为 nil 并打乱了您的计算。就是grid[idx + 1]为零!而且,自然地,你不能做 nil[idx2]。那是错误。

用 1 层边界声明你的网格,那么就不需要放置额外的 if/else 子句,也可以使用方向向量访问循环中的邻居。

#let say you want to delare 4x4 grid, declare grid of (row+2, col+2)
row, col, default_value = 4, 4, 0
grid = Array.new(row+2){Array.new(col+2,default_value)}

# store direction vectors dx and dy
dx = [-1, -1, -1, 0, 1, 1, 1, 0, 0]
dy = [-1, 0, 1, 1, 1, 0, -1, -1, 0]
(1..row).each do |i|
  (1..col).each do |j|
      puts (0..8).reduce(0) { |sum, k| sum + grid[i + dx[k]][j + dy[k]]}
end

您可以将邻居的枚举移动到一个单独的方法中:

def each_neighbor(x, y)
  raise IndexError unless within_bounds?(x, y)
  return enum_for(:each_neighbor, x, y) unless block_given?
  (y - 1).upto(y + 1) do |j|
    (x - 1).upto(x + 1) do |i|
      next unless within_bounds?(i, j)  # skip out of bounds cells
      next if i == x && j == y          # skip middle cell
      yield grid[i][j]
    end
  end
end

给定坐标 xy 此代码将简单地生成(有效)邻居。如果没有给出块,第一行 returns 一个枚举数。

代替嵌套upto loops, you could also utilize repeated_permutation生成偏移量:

[-1, 0, 1].repeated_permutation(2) do |dx, dy|
  next unless within_bounds?(x + dx, y + dy)
  next if dx.zero? && dy.zero? # skip middle cell
  yield grid[x + dx][y + dy]
end

然而,更重要的是,返回一个枚举器允许您从 Enumerable 链接方法,例如:

def grid
  [[1, 2, 1],
   [2, 3, 2],
   [1, 2, 1]]
end

each_neighbor(1, 1).sum    #=> 12
each_neighbor(1, 1).count  #=> 8

each_neighbor(0, 0).sum    #=> 7
each_neighbor(0, 0).count  #=> 3