将 numpy 数组添加到堆队列

Tom*_*mas 1 python arrays heap numpy

有人可以解释为什么以下代码会导致 ValueError 吗?

import heapq
import numpy as np

a = np.ones((2, 2), dtype=int)

states = []
heapq.heappush(states, (0, a))
heapq.heappush(states, (0, a.copy()))
Run Code Online (Sandbox Code Playgroud)

错误信息是:

Traceback (most recent call last):
  File "x.py", line 8, in <module>
    heapq.heappush(states, (0, a.copy()))
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Run Code Online (Sandbox Code Playgroud)

运行它而不将它添加a.copy()到堆中可以正常工作,第二个/后续的由于某种原因是一个问题。我确实理解数组有一个未知的真值方面,[True, False, True]并且不可能确定单个TrueFalse从中确定,但为什么heapq需要这样做?尤其是仅在第二种情况下?

MSe*_*ert 5

TL;DR:因为如果 numpy 数组包含多个元素,则它们不能转换为布尔值。


关于堆的一些信息:

堆“排序”它们的内容(因此项目必须实现,<但这是一个实现细节)。

但是,您可以heap通过tuple为项目创建s 来将项目插入到 中,其中第一个元素是某个值,第二个元素是数组。

比较元组首先检查第一项是否相等,如果相等,则检查第二项是否相等,依此类推,直到它们不相等,然后它会检查它是更小(当操作为 时<)还是更大(为>)。然而元组是在 C 中实现的,并且==检查与 Python 中的检查有点不同。它使用PyObject_RichCompareBool. 尤其是“注释”在这里很重要

如果o1o2是同一个对象,PyObject_RichCompareBool()将始终返回 1 forPy_EQ和 0 for Py_NE

现在让我们转到 numpy 数组:

如果numpy.arrayabool包含多个项目,则无法将 a 转换为 a :

>>> arr = np.array([1,2,3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Run Code Online (Sandbox Code Playgroud)

一个if检查隐式转换的条件为布尔值:

>>> if arr: pass
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Run Code Online (Sandbox Code Playgroud)

即使在比较 numpy-arrays 之后,它们仍然是 numpy 数组:

>>> arr > arr
array([False, False], dtype=bool)
>>> arr == arr
array([ True,  True], dtype=bool)
Run Code Online (Sandbox Code Playgroud)

所以这些不能用以下方法评估==

>>> if arr == arr: pass
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Run Code Online (Sandbox Code Playgroud)

因此,您不能将具有多个元素的 numpy 数组转换为布尔值!然而现在有趣的部分来了:heapq-module 使用PyObject_RichCompareBool()它可以检查两个数组是否相等,但当且仅当它们相同!

这就是为什么它可以与多次传入的相同数组一起使用,但在复制它时却失败了:

>>> arr is arr
True
>>> arr is arr.copy()
False
Run Code Online (Sandbox Code Playgroud)