如何搜索数组列表
考虑下面这个包含两个数组的列表:
from numpy import array
a = array([0, 1])
b = array([1, 0])
l = [a,b]
然后,正确找到 a
的索引会得到:
l.index(a)
>>> 0
而这对于 b
就不管用了:
l.index(b)
ValueError: The truth value of an array with more than one element is ambiguous.
Use a.any() or a.all()
我觉得,调用列表的 .index
函数在处理 numpy 数组的列表时是行不通的。
有没有人能解释一下这个情况?到目前为止,我总是通过把数组转换成字符串来解决这个问题,这样做有点笨。有没有人知道更优雅、更快速的解决办法?
相关文章:
- 暂无相关问题
2 个回答
这个错误是因为numpy在比较数组元素时的处理方式造成的,具体可以参考这个链接:链接。
我猜测,因为第一个元素是你要查找的实例,所以你能得到它的索引,但当你试图将第一个元素和第二个元素进行比较时,就会出现这个错误。
我觉得你可以用类似这样的方式:
[i for i, temp in enumerate(l) if (temp == b).all()]
来获取一个包含相等数组索引的列表,不过我对python不是很精通,可能还有更好的解决方案(这个方法似乎是有效的...)
其实,关键问题在于为什么 l.index[a]
能返回正确的值。因为 numpy 数组在处理相等性时有自己特别的方式:当你写 l[1] == b
时,它返回的是一个数组,而不是简单的真或假。这是因为它在比较每个单独的值。在这个例子中,它返回了 array([ True, True], dtype=bool)
,这个结果不能直接转换成一个布尔值,所以就出现了错误。
实际上,Python 使用了一种丰富的比较方式,特别是 PyObject_RichCompareBool 来将你要找的值与列表中的每个元素进行比较。这意味着它首先会检查身份(a is b
),然后再检查相等性(a == b
)。所以对于第一个元素来说,因为 a is l[0]
是真的,所以返回的是索引 0。
但是对于其他任何元素,和第一个元素的身份比较都是假的,这样在进行相等性测试时就会出错。(感谢 Ashwini Chaudhary 在评论中的精彩解释)。
你可以通过测试一个新复制的数组来确认这一点,这个数组的元素和 l[0]
是一样的:
d = array([0,1])
l.index(d)
它会出现同样的错误,因为身份比较是假的,而相等性测试会引发错误。
这意味着你不能依赖任何使用比较的列表方法(比如 index、in、remove),而必须使用像 @orestiss 提出的自定义函数。或者,由于使用 numpy 数组的列表似乎很麻烦,你可以考虑将数组进行封装:
>>> class NArray(object):
def __init__(self, arr):
self.arr = arr
def array(self):
return self.arr
def __eq__(self, other):
if (other.arr is self.arr):
return True
return (self.arr == other.arr).all()
def __ne__(self, other):
return not (self == other)
>>> a = array([0, 1])
>>> b = array([1, 0])
>>> l = [ NArray(a), NArray(b) ]
>>> l.index(NArray(a))
0
>>> l.index(NArray(b))
1