我在python中创建一个Sudoku,我需要创建一个3x3矩阵,其中每个值都代表板上的一个框。如果方框中有一个值实例,则该值将为False,如果没有,则为True。
目前我有
temp_board = ma.masked_where(board == value, board, True)
boxes = np.full((3, 3), False)
for x in range(3):
for y in range(3):
boxes[x, y] = not np.any(temp_board.mask[x * 3:(x + 1) * 3, y * 3:(y + 1) * 3])板是包含数字0-9的9x9矩阵,但数值只能等于1-9。
下面是输出应该是什么样子的示例
# input
board = np.array([[4, 0, 9, 0, 7, 2, 0, 1, 3],
[7, 0, 2, 8, 3, 0, 6, 0, 0],
[0, 1, 6, 0, 4, 9, 8, 7, 0],
[2, 0, 0, 1, 0, 0, 0, 6, 0],
[5, 4, 7, 0, 0, 0, 2, 0, 0],
[6, 9, 0, 0, 0, 4, 0, 3, 5],
[8, 0, 3, 4, 0, 0, 0, 0, 6],
[0, 0, 0, 0, 0, 3, 1, 0, 0],
[0, 6, 0, 9, 0, 0, 0, 4, 0]])
value = 9
# output
[[False False True]
[False True True]
[ True False True]]我正在使用的方法是工作,但效率非常低,我想知道是否有更快的方法来做到这一点。
发布于 2022-11-25 08:32:28
有一种方法,不是很微妙,而是快速,就是有一个查找索引表。
look=np.zeros((9,9,9), dtype=bool)
look[0,:3,:3]=True
look[1,:3,3:6]=True
look[2,:3,6:]=True
look[3,3:6,:3]=True
look[4,3:6,3:6]=True
look[5,3:6,6:]=True
look[6,6:,:3]=True
look[7,6:,3:6]=True
look[8,6:,6:]=True
def inblock(board, blnum, val):
return val in board[look[blnum]]为了直接得到矩阵,你可以
~(look*board == value).any(axis=(1,2)).reshape(3,3)look*board是一个9x9x9矩阵,每个块只过滤一个块((look*board)[k]在任何地方都包含0,但在块k中,这是板的副本)。
(look*board == value)是它的一个布尔版本。
所以(look*board == value).any(axis=(1,2))是9个值,真当且仅当block[k] contains value。
因为我使用了一个一维块数组,你可以重塑得到3x3矩阵。
然后否定结果来模仿你的输出。
请注意,构建look表肯定有更微妙的方法。例如,使用您自己的For循环,稍微修改一下。但那只需要一次。
替代方案
更直截了当(坦白地说,当我开始思考你的问题时,我想要的是:
look=np.zeros((3,3,9,9), dtype=bool)
for i in range(3):
for j in range(3):
look[i,j,i*3:(i+1)*3,j*3:(j+1)*3] = True
~np.einsum('ijkl,kl', look, board==value)事实上,我使用(3,3,9,9)形状,然后避免整形实际上不是重点(这是相同的成本,只是一个演示问题)。对于以前的解决方案我本可以这么做的。
这一次,我使用一个双循环来创建look表,这也不是事实。再说一遍,我以前也可以这么做的。改变的不是look。只是einsum的用法。这并不比我以前的解决方案好。但这是我最初的想法:使用一种矩阵乘法。
时差
~(look*board == value).any(axis=(2,3)):18.9μs (注:这是我以前的解决方案,适合于(3,3,9,9)形状
~np.einsum('ijkl,kl', look, board==value):13.6μs
所以,我的第二个解决方案不仅仅是我想要的那个。但它似乎也更快。
https://stackoverflow.com/questions/74569356
复制相似问题