这是一种方法-
def sum_by_signs(a):
m1 = a<0
m2 = a>0
m0 = a==0 # or ~m1 & ~m2
p = np.flatnonzero(m0[:-1] | np.diff(m1) | np.diff(m2))+1
return np.add.reduceat(a, np.r_[0,p])
或者将 np.r_[0 部分带入布尔构造部分 -
def sum_by_signs_v2(a):
m1 = a<0
m2 = a>0
m0 = a==0 # or ~m1 & ~m2
p = np.flatnonzero(np.r_[True, m0[:-1] | np.diff(m1) | np.diff(m2)])
return np.add.reduceat(a, p)
说明
我们开始考虑根据符号变化或遇到一系列 0 时将数组拆分为“孤岛”,在这种情况下,我们希望将每个元素拆分为一个单独的元素。通过拆分,将其视为列表列表,如果这样更容易理解。现在,游戏是我们如何获得这些分裂。我们需要表示这些岛屿的开始、停止索引的索引。如前所述,共有三种情况,符号从+ 变为- 或反之亦然或0 序列。
因此,布尔掩码的结构用于为这些索引提供一次性切片,以检测从+ 到- 的符号变化,反之亦然,结合np.diff(m1) | np.diff(m2)。 m0[:-1] 的最后一个是0s 的序列。然后将这些索引馈送到np.add.reduceat 以获得间隔总和。
示例运行 -
In [208]: a
Out[208]: array([ 0, 0, 0, -1, -1, 0, 1, 2, 1, 1, 0, -1, 0, 1, 1, -1, -2])
In [209]: sum_by_signs(a)
Out[209]: array([ 0, 0, 0, -2, 0, 5, 0, -1, 0, 2, -3])
In [211]: a
Out[211]: array([ 1, 2, 0, -1, -1, 0, 1, 2, 1, 1, 0, -1, 0, 1, 1, -1, -2])
In [212]: sum_by_signs(a)
Out[212]: array([ 3, 0, -2, 0, 5, 0, -1, 0, 2, -3])
In [214]: a
Out[214]:
array([ 1, 2, 0, -1, -1, 0, 1, 2, 1, 1, 0, -1, 0, 1, 1, -1, -2,
0])
In [215]: sum_by_signs(a)
Out[215]: array([ 3, 0, -2, 0, 5, 0, -1, 0, 2, -3, 0])