Python迭代数组触发多元素数组真值歧义ValueError报错求解
numpy数组成员判断触发真值歧义错误的解决方案
出错代码
def incrementalAdd(self,p,eps,Minpts): self.num = self.num + 1 print("\nADDING point "+str(self.num)) self.visited = [] self.newCores = [] UpdSeedIns = [] foundClusters = [] NeighbourPoints = self.regionQuery(p,eps) if len(NeighbourPoints) >= int(Minpts): self.newCores.append(p) self.visited.append(p) for pt in NeighbourPoints: print('pt:') print(pt) print('self.visited:') print(self.visited) i=0 for i in range(len(pt)): if pt[i] not in self.visited:
运行时输出
pt: [766.13 389.14] self.visited: [array([766.13, 389.14])]
抛出错误
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
错误原因
self.visited中存储的元素是numpy数组类型,Python的in关键字在做成员校验时,会将待匹配对象和列表内每个元素执行==比较。两个numpy数组做==运算返回的是逐元素对比的布尔数组,不是单个布尔值,Python无法判定这个多元素布尔数组的整体真假,就会抛出该错误。- 现有代码逻辑存在偏差:内层循环
for i in range(len(pt))是在逐个提取坐标点的x、y单值,再和列表中存储的完整坐标数组做匹配,本身就不符合判断“点是否被访问过”的业务逻辑。
修复方案
根据实际需求二选一即可:
- 保留列表存储numpy数组的写法,删除内层遍历坐标维度的多余循环,用numpy原生的数组相等方法判断点是否存在:
for pt in NeighbourPoints: print('pt:') print(pt) print('self.visited:') print(self.visited) # 直接判断整个pt是否在已访问列表中 is_visited = any(np.array_equal(pt, v_pt) for v_pt in self.visited) if not is_visited: # 补充后续未访问点的处理逻辑
- 优化存储结构提升判断效率:将存入
self.visited的numpy数组转为可哈希的元组类型,数据量大时可以直接用set存储,in判断的时间复杂度从O(n)降到O(1):
def incrementalAdd(self,p,eps,Minpts): self.num = self.num + 1 print("\nADDING point "+str(self.num)) self.visited = set() # 改成集合提升判断效率 self.newCores = [] UpdSeedIns = [] foundClusters = [] NeighbourPoints = self.regionQuery(p,eps) if len(NeighbourPoints) >= int(Minpts): self.newCores.append(p) self.visited.add(tuple(p)) # 存的时候转元组 for pt in NeighbourPoints: pt_tuple = tuple(pt) print('pt:') print(pt) print('self.visited:') print(self.visited) if pt_tuple not in self.visited: # 补充后续未访问点的处理逻辑
注意:如果后续要对访问过的点做顺序遍历,用列表存元组即可;如果只需要做存在性判断,优先用set存储。
内容的提问来源于stack exchange,提问作者ttina
相关产品推荐
相关产品推荐

