繁体   English   中英

覆盖字典行为Python3

[英]Overriding dictionary behaviour Python3

我是使用Python的初学者,正在尝试在字典中使用搜索功能来搜索键为点坐标(2)的numpy数组的键。 所以,我想要的是:一个字典,其键是numpy数组,其值是整数。 然后,将使用in运算符使用一些公差度量(numpy.allclose函数)来比较键。 我知道numpy数组不是可散列的,所以我必须重写getitemsetitem函数(基于我在如何正确地将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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM