PAYATHON 2026

如何用 NumPy 替换 Python 表达式中的 and,性能会受影响吗?

数据小许

可以用 np.all、np.logical_and.reduce 或 & 替换这里的 and,判断结果相同。但这些写法不会保留 and 的短路求值,也不保证更快。对于题目中的小数组,保留原写法是合理的选择。

用 np.all 汇总四个判断

原逻辑要求四条边各自至少出现一次 K。可以先对每条边调用 np.any,再判断四个结果是否全部为真:

r = np.all([
    np.any(a[0, :] == K),
    np.any(a[-1, :] == K),
    np.any(a[:, 0] == K),
    np.any(a[:, -1] == K),
])

传给 np.all 的是四个布尔标量,因此它并不要求边上的所有元素都等于 K。

也可以把 np.all 换成 np.logical_and.reduce:

r = np.logical_and.reduce([
    np.any(a[0, :] == K),
    np.any(a[-1, :] == K),
    np.any(a[:, 0] == K),
    np.any(a[:, -1] == K),
])

这两种写法都会先计算列表中的四个结果,再进行汇总。

用 & 直接连接结果

每次 np.any 返回的都是布尔标量,也可以这样写:

r = (
    np.any(a[0, :] == K)
    & np.any(a[-1, :] == K)
    & np.any(a[:, 0] == K)
    & np.any(a[:, -1] == K)
)

对于这里的布尔结果,& 表示逻辑与。它同样不会短路,四次 np.any 都会执行。

如果直接组合数组比较表达式,应给每个比较加括号,例如 (x == K) & (y == K)。不能直接把四条边的比较结果逐元素相与来替代原逻辑:这样会改变判断含义,当 N != M 时还可能遇到形状不匹配。

为什么不一定更快?

原表达式中的 and 在某个条件为假后会跳过后面的条件。例如,第一行没有 K 时,就不需要检查剩余三条边。

换成 NumPy 汇总函数后,仍要检查四条边,还需要构造列表并汇总结果。使用 & 不需要列表,但也失去了短路求值。把四个布尔值交给 NumPy 连接,并不意味着计算会更高效。

也可以先计算一次完整掩码:

mask = a == K
r = (
    mask[0, :].any()
    and mask[-1, :].any()
    and mask[:, 0].any()
    and mask[:, -1].any()
)

不过,这会比较整个数组中的 N * M 个元素,并创建完整的布尔数组。原写法只比较需要检查的边界。如果其他地方也要使用这个掩码,可以考虑复用;仅为当前判断创建它,不一定划算。

小数组场景如何选择?

对于 K <= 5、N, M < 32 的范围,建议先保留原来的 and。如果更喜欢集中汇总条件的形式,也可以使用 np.all,但要注意求值方式不同。

具体耗时需要在实际环境中测量。比较时应提前生成数组,把随机数生成排除在计时之外,并覆盖第一条边就失败、后续边失败、四条边都通过等情况。没有这样的测量,就无法判断哪种写法在你的工作负载中更快,也无法确定性能差异是否明显。

这些 NumPy 写法通常返回 np.bool_;如果后续接口要求 Python 的 bool,可以使用 bool(r) 转换。

备注:内容仅供参考。