我一直在尝试学习numpy一段时间,并决定编写一些复杂的练习来验证我是否理解了一切,有一个对我来说似乎有点奇怪。
目标是编写一个只使用numpy库和numpy索引的函数(没有for/while循环,没有if语句),它将清除矩阵中所有的偶数环。
首先,我试着得到一个给定的环,这里有一个函数:这里m是矩阵,l是环的层数,0是环的外层
def get_ring(m, l):
n = m.shape[0]
return np.concatenate((m[l:n-l, l:n-l], m[(l+1):n-l, -(l+1)], m[-(l+1), -(l+2):l:-1], m[n-(l+1):l:-1, l]))
然后,我进一步编写了这个函数,使用np将一个环归零。其中和的一些逻辑组成一个环的4个部分下面是这个函数
def zero_ring(m, l):
n = m.shape[0]
m[l:n-l, l:n-l] = np.where(np.logical_or(np.logical_or(np.arange(n-l-l)[:, None] == 0, np.arange(n-l-l) == n-l-l-1),
np.logical_or(np.arange(n-l-l)[::-1][:, None] == 0, np.arange(n-l-l)[::-1] == n-l-l-1)), 0, m[l:n-l, l:n-l])
return m
举个例子这是一个5x5数组的输出
print(zero_ring(a, 1))
[[ 1 2 3 4 5]
[ 6 0 0 0 10]
[11 0 13 0 15]
[16 0 0 0 20]
[21 22 23 24 25]]
现在剩下的就是写这个函数,把所有的偶数环归零,但是我不知道如果不使用for循环,我怎么能做到这一点,因为有了for循环,它将是立即的。
您的代码对我来说有点复杂,如果您可以将其扩展到多个环而无需任何手动循环。我认为如果你以分段的方式构建每个环,将很难实现,但请随意证明我是错的:)。
也就是说,我确实知道另一种有趣的方法来构建环状结构。考虑这个数组:
[3, 2, 1, 0, 1, 2, 3]
和数组中每对整数之间的最大值:
3 2 1 0 1 2 3
/---------------------
3 | 3 3 3 3 3 3 3 |
2 | 3 2 2 2 2 2 3 |
1 | 3 2 1 1 1 2 3 |
0 | 3 2 1 0 1 2 3 |
1 | 3 2 1 1 1 2 3 |
2 | 3 2 2 2 2 2 3 |
3 | 3 3 3 3 3 3 3 |
---------------------/
你要找的环就是这个数组中的偶数和奇数元素!
可以用np.abs
+np.arange
:
def center(size):
return np.abs(np.arange(-size // 2 + 1, size // 2 + 1))
>>> center(7)
array([3, 2, 1, 0, 1, 2, 3])
并创建两个这样的数组之间的成对最大值,或者使用广播,或者使用np.maximum.outer
。为了区分奇偶环,你可以用2取模。
def ring_mask(h, w):
rows = center(h)
cols = center(w)
return (np.maximum.outer(rows, cols) % 2).astype(bool)
最后,将掩码与np.where
结合使用:
def zero_rings(arr):
mask = ring_mask(*arr.shape)
return np.where(~mask, arr, 0)
import numpy as np
arr = np.arange(1, 82).reshape(9, 9)
out = zero_rings(arr)
:
array([[ 1, 2, 3, 4, 5, 6, 7, 8, 9],
[10, 0, 0, 0, 0, 0, 0, 0, 18],
[19, 0, 21, 22, 23, 24, 25, 0, 27],
[28, 0, 30, 0, 0, 0, 34, 0, 36],
[37, 0, 39, 0, 41, 0, 43, 0, 45],
[46, 0, 48, 0, 0, 0, 52, 0, 54],
[55, 0, 57, 58, 59, 60, 61, 0, 63],
[64, 0, 0, 0, 0, 0, 0, 0, 72],
[73, 74, 75, 76, 77, 78, 79, 80, 81]])
PS:你可能需要也可能不需要反转掩码(或在% 2
之前加1),这取决于你认为哪些环是偶数,哪些环是奇数。