简体   繁体   English

处理python中2D列表边界检查的最佳方法?

[英]Best way to handle boundary check for 2D list in python?

I have one 2D list like following, I want to change cell value from 1 to 0 if the cell surrounding cell is 0 like 我有一个如下的2D列表,如果要将像元周围的像元设为0,我想将像元值从1更改为0

from
[
  [1, 0, 1, 0, 1],
  [0, 0, 1, 0, 0],
  [0, 0, 0, 0, 0],
  [1, 0, 1, 0, 1],
  [0, 0, 0, 0, 0],
  [1, 0, 1, 0, 1],
]
To
[
  [0, 0, 1, 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],
]

I think I can use 8 if/else logic to check but wondering if there is a better or clean way to do it? 我想我可以使用8个if / else逻辑进行检查,但想知道是否有更好或更干净的方法来做到这一点?

I will make use of python generator to get the valid neighbors, and use the all to check if all the neighbors are zero. 我将利用python生成器获取有效的邻居,并使用all检查所有邻居是否为零。

def update_cell(grid):
    if not grid or not grid[0]:
        return
    m, n = len(grid), len(grid[0])

    def is_valid(i, j):
        return 0 <= i < m and 0 <= j < n

    def neighbors(i, j):
        for di, dj in [(0, 1), (0, -1), (1, 0), (-1, 0), (-1, 1), (-1, -1), (1, -1), (1, 1)]:
            ni, nj = i+di, j+dj
            if is_valid(ni, nj):
                yield ni, nj

    for i in range(m):
        for j in range(n):
            if grid[i][j] and all(not grid[ni][nj] for ni, nj in neighbors(i, j)):
                grid[i][j] = 0


if __name__ == "__main__":

    grid = [
        [1, 0, 1, 0, 1],
        [0, 0, 1, 0, 0],
        [0, 0, 0, 0, 0],
        [1, 0, 1, 0, 1],
        [0, 0, 0, 0, 0],
        [1, 0, 1, 0, 1],
    ]

    update_cell(grid)

    print(grid)

   # prints
   #[[0, 0, 1, 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]]

Sum the 3x3 list-list around the point in question. 对有关点周围的3x3列表列表求和。 Iff the sum is 1 (value of the center cell), you set it to 0 . 如果总和为1 (中心单元格的值),则将其设置为0

To pick out the 3x3 segment, you can 要挑选3x3细分,您可以

  • Iterate over the 3x3 slices you want. 遍历所需的3x3切片。
  • Use slices of slices to make a new 3x3 segment for each check. 使用切片切片为每个检查创建一个新的3x3段。
  • Convert your list-list to a NumPy 2D array; 将您的列表转换为NumPy 2D数组; NumPy has nice slicing capabilities. NumPy具有良好的切片功能。

I'd write the if's, but generating neighbors as in the other answer is elegant. 我会写if,但是像在其他答案中那样生成邻居是很优雅的。

If you can alter the data structure and need speed then you can use ghost cells. 如果您可以更改数据结构需要速度,则可以使用幻像单元。

Surround your grid with zeros like this : 用零包围您的网格,如下所示:

       0 0 0 0
1 2    0 1 2 0
4 5    0 4 5 0
       0 0 0 0

Then you can iterate from 1..n-1 and always have all neighbours 然后您可以从1..n-1进行迭代,并始终拥有所有邻居

One way would be: 一种方法是:

def neighbors(m,r,c):
    return sum((
        sum(m[r-1][max(0,c-1):c+2]) if 0 <= r-1 < len(m) else 0,
        sum(m[r  ][max(0,c-1):c+2]) if 0 <= r   < len(m) else 0,
        sum(m[r+1][max(0,c-1):c+2]) if 0 <= r+1 < len(m) else 0,
    )) - m[r][c]

It takes the sum of the 3x3 square around the (r,c) element, then subtracts the value at (r,c) . 它取(r,c)元素周围的3x3平方和,然后减去(r,c)的值。

There are innumerable ways to clean this up based on preference, for example: 有多种方法可以根据喜好进行清理,例如:

def neighbors(m,r,c):
    return sum(
        sum(m[x][max(0,c-1):c+2]) for x in [r-1,r,r+1] if 0 <= x < len(m)
    ) - m[r][c]

The only real somewhat clever thing here is that you can sort of side-step out of bounds errors by using slicing. 唯一真正聪明的地方是,您可以使用切片来规避越界错误。 So x = [1,2,3]; print(x[100:200]) 所以x = [1,2,3]; print(x[100:200]) x = [1,2,3]; print(x[100:200]) will just print an empty list, no IndexError . x = [1,2,3]; print(x[100:200])只会打印一个空列表,没有IndexError

Do I think you should use this code instead of a simple nested for loop? 我认为您应该使用此代码而不是简单的嵌套for循环吗? Almost definitely not. 几乎肯定不是。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM