如何搜索数组列表

4 投票
2 回答
1300 浏览
提问于 2025-05-10 23:46

考虑下面这个包含两个数组的列表:

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 个回答

0

这个错误是因为numpy在比较数组元素时的处理方式造成的,具体可以参考这个链接:链接

我猜测,因为第一个元素是你要查找的实例,所以你能得到它的索引,但当你试图将第一个元素和第二个元素进行比较时,就会出现这个错误。

我觉得你可以用类似这样的方式:

[i for i, temp in enumerate(l) if (temp == b).all()]

来获取一个包含相等数组索引的列表,不过我对python不是很精通,可能还有更好的解决方案(这个方法似乎是有效的...)

1

其实,关键问题在于为什么 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

撰写回答