我刚开始学习Python
,感觉还不错,我甚至可以说Python非常性感,直到我需要移动一个4×4矩阵的内容,我打算用它来构建一个2048游戏的演示,游戏的演示在这里这里。我有这样一个函数:
def cover_left(matrix): new=[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]] for i in range(4): count=0 for j in range(4): if mat[i][j]!=0: new[i][count]=mat[i][j] count+=1 return new
如果你像这样调用这个函数,它会执行以下操作:
cover_left([ [1,0,2,0], [3,0,4,0], [5,0,6,0], [0,7,0,8] ])
它会将零移到左边,产生以下结果:
[ [1, 2, 0, 0], [3, 4, 0, 0], [5, 6, 0, 0], [7, 8, 0, 0]]
请问有人能帮我用numpy
的方式实现这个功能吗?我相信这样会更快,代码也会更少(我是在深度优先搜索算法中使用),更重要的是,实现cover_up
、cover_down
和cover_left
的功能。
`cover_up` [ [1, 7, 2, 8], [3, 0, 4, 0], [5, 0, 6, 0], [0, 0, 0, 0]]`cover_down` [ [0, 0, 0, 0], [1, 0, 2, 0], [3, 0, 4, 0], [5, 7, 6, 8]]`cover_right` [ [0, 0, 1, 2], [0, 0, 3, 4], [0, 0, 5, 6], [0, 0, 7, 8]]
回答:
这里有一个受这篇文章
启发的向量化方法,并推广到覆盖所有四个方向的非零
值 –
def justify(a, invalid_val=0, axis=1, side='left'): """ 调整二维数组 参数 ---------- A : ndarray 输入数组,需要调整 axis : int 调整的轴 side : str 调整的方向。可以是'left', 'right', 'up', 'down' 对于axis=1,应该是'left'或'right',对于axis=0,应该是'up'或'down'。 """ if invalid_val is np.nan: mask = ~np.isnan(a) else: mask = a!=invalid_val justified_mask = np.sort(mask,axis=axis) if (side=='up') | (side=='left'): justified_mask = np.flip(justified_mask,axis=axis) out = np.full(a.shape, invalid_val) if axis==1: out[justified_mask] = a[mask] else: out.T[justified_mask.T] = a.T[mask.T] return out
示例运行 –
In [473]: a # 输入数组Out[473]: array([[1, 0, 2, 0], [3, 0, 4, 0], [5, 0, 6, 0], [6, 7, 0, 8]])In [474]: justify(a, axis=0, side='up')Out[474]: array([[1, 7, 2, 8], [3, 0, 4, 0], [5, 0, 6, 0], [6, 0, 0, 0]])In [475]: justify(a, axis=0, side='down')Out[475]: array([[1, 0, 0, 0], [3, 0, 2, 0], [5, 0, 4, 0], [6, 7, 6, 8]])In [476]: justify(a, axis=1, side='left')Out[476]: array([[1, 2, 0, 0], [3, 4, 0, 0], [5, 6, 0, 0], [6, 7, 8, 0]])In [477]: justify(a, axis=1, side='right')Out[477]: array([[0, 0, 1, 2], [0, 0, 3, 4], [0, 0, 5, 6], [0, 6, 7, 8]])
通用情况(ndarray)
对于ndarray,我们可以修改为 –
def justify_nd(a, invalid_val, axis, side): """ 调整ndarray中有效元素(非invalid_val)。 参数 ---------- A : ndarray 输入数组,需要调整 invalid_val : scalar 无效值 axis : int 调整的轴 side : str 调整的方向。必须是'front'或'end'。 因此,使用'front'时,有效元素被推到前面, 使用'end'时,有效元素被推到指定轴的末尾。 """ pushax = lambda a: np.moveaxis(a, axis, -1) if invalid_val is np.nan: mask = ~np.isnan(a) else: mask = a!=invalid_val justified_mask = np.sort(mask,axis=axis) if side=='front': justified_mask = np.flip(justified_mask,axis=axis) out = np.full(a.shape, invalid_val) if (axis==-1) or (axis==a.ndim-1): out[justified_mask] = a[mask] else: pushax(out)[pushax(justified_mask)] = pushax(a)[pushax(mask)] return out
示例运行 –
输入数组:
In [87]: aOut[87]: array([[[54, 57, 0, 77], [77, 0, 0, 31], [46, 0, 0, 98], [98, 22, 68, 75]], [[49, 0, 0, 98], [ 0, 47, 0, 87], [82, 19, 0, 90], [79, 89, 57, 74]], [[ 0, 0, 0, 0], [29, 0, 0, 49], [42, 75, 0, 67], [42, 41, 84, 33]], [[ 0, 0, 0, 38], [44, 10, 0, 0], [63, 0, 0, 0], [89, 14, 0, 0]]])
到'front'
,沿axis =0
:
In [88]: justify_nd(a, invalid_val=0, axis=0, side='front')Out[88]: array([[[54, 57, 0, 77], [77, 47, 0, 31], [46, 19, 0, 98], [98, 22, 68, 75]], [[49, 0, 0, 98], [29, 10, 0, 87], [82, 75, 0, 90], [79, 89, 57, 74]], [[ 0, 0, 0, 38], [44, 0, 0, 49], [42, 0, 0, 67], [42, 41, 84, 33]], [[ 0, 0, 0, 0], [ 0, 0, 0, 0], [63, 0, 0, 0], [89, 14, 0, 0]]])