有一个快速的O(n log n) 有效且矢量化的 Numpy 实现。
这个想法是在x(和np.unique)中找到唯一值,并为每个唯一值定位其第一个位置。然后你可以在x中选择值v,如果之前找到-v和v < 0。要查找它之前是否找到,您可以在已排序的唯一值(使用np.searchsorted)中执行二分法,以查找当前索引是否大于找到的索引(在唯一值中)。
这是生成的代码:
xUnique, xFirstPos = np.unique(x, return_index=True)
xIsNeg = x < 0
xNeg = -x
xNegUniquePos = np.searchsorted(xUnique, xNeg)
xNegIsFound = xUnique[xNegUniquePos] == xNeg
xHasNegBefore = np.logical_and(xNegIsFound, xFirstPos[xNegUniquePos] < np.arange(len(x)))
result = x[np.logical_and(xIsNeg, np.logical_not(xHasNegBefore))]
print(result)
以下是一些示例的结果:
x = np.array([20000, 700, 1000, -5000, -250, 30, -1000, 50, -30, 75, -999])
result = np.array([-5000, -250, -999])
x = np.array([-5, 5, -5])
result = np.array([-5])
以下是大小为 100_000 的随机数组的时序(33% 的负值在 -1_000_000 到 2_000_000 范围内):
Mad Physicist's Numpy implementation: 38900.0 ms
Emi OB's implementation: 1360.0 ms (incorrect so far)
Mad Physicist's pure Python implementation: 40.0 ms
This implementation: 14.1 ms
到目前为止,这个实现比其他实现快得多。对于这个输入大小,Mad Physicist 的 Numpy 实现占用 几个 GiB 的内存,而其他解决方案(包括这个)占用不超过 10 MiB,这毫无价值。