[英]Overriding dictionary behaviour Python3
我是使用Python的初学者,正在尝试在字典中使用搜索功能来搜索键为点坐标(2)的numpy数组的键。 所以,我想要的是:一个字典,其键是numpy数组,其值是整数。 然后,将使用in运算符使用一些公差度量(numpy.allclose函数)来比较键。 我知道numpy数组不是可散列的,所以我必须重写getitem和setitem函数(基于我在如何正确地将dict子类化并重写__getitem__和__setitem__中找到的内容 )。 但是,如何使这些可哈希化以将它们添加为字典中的键? 在这种情况下,如何覆盖in运算符的行为?
谢谢您的帮助!
Numpy数组不可散列,而元组则可。 因此,如果将数组变成元组,则可以对数组进行哈希处理。 从理论上讲,如果您也事先对其进行了四舍五入,则可以利用快速查找的优势,因为您现在拥有离散点。 但是,由于四舍五入是使用十进制基数完成的,而数字是以二进制存储的,因此在重新转换期间会遇到分辨率问题。 可以通过将其转换为可缩放的整数来规避此问题,但这会使一切变慢。
最后,您只需要编写一个类即可在数组和元组之间进行实时转换,就可以了。
一个实现可能看起来像这样:
import numpy as np
class PointDict(dict):
def __init__(self, precision=5):
super(PointDict, self).__init__()
self._prec = 10**precision
def decode(self, tup):
"""
Turns a tuple that was used as index back into a numpy array.
"""
return np.array(tup, dtype=float)/self._prec
def encode(self, ndarray):
"""
Rounds a numpy array and turns it into a tuple so that it can be used
as index for this dict.
"""
return tuple(int(x) for x in ndarray*self._prec)
def __getitem__(self, item):
return self.decode(super(PointDict, self).__getitem__(self.encode(item)))
def __setitem__(self, item, value):
return super(PointDict, self).__setitem__(self.encode(item), value)
def __contains__(self, item):
return super(PointDict, self).__contains__(self.encode(item))
def update(self, other):
for item, value in other.items():
self[item] = value
def items(self):
for item in self:
yield (item, self[item])
def __iter__(self):
for item in super(PointDict, self).__iter__():
yield self.decode(item)
当查找很多点时,具有矢量化批处理写入/查找功能的纯numpy解决方案可能会更好。 但是,此解决方案易于理解和实施。
代替numpy数组,使用2元组的float作为键。 元组是不可哈希的,因为它们是不可变的。
Python字典在后台使用哈希表来快速查找键。
编写closeto
函数并不难。
def closeto(a, b, limit=0.1):
x, y = a
p, q = b
return (x-p)**2 + (y-q)**2 < limit**2
这可用于查找接近的点。 但是随后您必须遍历所有键,因为键查找是准确的。 但是,如果你在修真做到这一点的迭代,它比它快得多for
-loop。
测试(在IPython中,使用Python 3):
In [1]: %cpaste
Pasting code; enter '--' alone on the line to stop or use Ctrl-D.
: def closeto(a, b, limit=0.1):
: x, y = a
: p, q = b
: return (x-p)**2 + (y-q)**2 < limit**2
:--
In [2]: d = {(0.0, 0.0): 12, (1.02, 2.17): 32, (2.0, 4.2): 23}
In [3]: {k: v for k, v in d.items() if closeto(k, (1.0, 2.0), limit=0.5)}
Out[3]: {(1.02, 2.17): 32}
将数组转换为可哈希的元组:
In [18]: a1 = np.array([0.5, 0.5])
In [19]: a2 = np.array([1.0, 1.5])
In [20]: d = {}
In [21]: d[tuple(a1)] = 14
In [22]: d[tuple(a2)] = 15
In [23]: d
Out[23]: {(0.5, 0.5): 14, (1.0, 1.5): 15}
In [24]: a3 = np.array([0.5, 0.5])
In [25]: a3 in d
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-25-07c81d61b999> in <module>()
----> 1 a3 in d
TypeError: unhashable type: 'numpy.ndarray'
In [26]: tuple(a3) in d
Out[26]: True
不幸的是,由于您想对比较施加公差,因此您没有太多选择,只能遍历所有键以寻找“接近”匹配,无论是将其实现为函数还是内联。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.