在Python中创建700k项的字典?

在Python中创建700k项的字典?,python,dictionary,hash,performance,Python,Dictionary,Hash,Performance,我有一个名为Point的类,它的属性只有x\u坐标和y\u坐标浮动。我有大约700000个点对象,我想存储在字典中 字典的键是点对象,相应的值是区域对象,其中包含大约1000个点。基本上,键p属于值r,这意味着点对象属于特定区域对象 长话短说,这是我试图执行的原始循环: look_up_table = {} for region in all_regions_list: for point in region.points_list: look_up_table[poin

我有一个名为
Point
的类,它的属性只有
x\u坐标
y\u坐标
浮动。我有大约700000个点对象,我想存储在字典中

字典的键是
对象,相应的值是
区域
对象,其中包含大约1000个点。基本上,键
p
属于值
r
,这意味着点对象属于特定区域对象

长话短说,这是我试图执行的原始循环:

look_up_table = {}
for region in all_regions_list:
    for point in region.points_list:
        look_up_table[point] = region
在所有区域中,大约有700000个点对象已加载到内存中。因此,代码中的第4行可能会执行700k次,字典将有700k(键,值)对

假设每个点对象占用1KB的内存(这是不可能的),超过700000个点将占用约680MB的内存。我有超过3GB的空闲内存。此外;这些点和区域对象已加载到内存中

然而,这些简单的4行需要永远完成,我已经等了大约2个小时,没有运气。。。只需一个小时就可以散列10k个对象

所以,我的问题是,我有没有做错什么?是否有另一种方法可以在内存中存储700k对象,并能够在O(1)时间内查找某个键

顺便说一下,下面是
类的重写方法:

def __hash__(self, *args, **kwargs):
        """ overriden hash method """
        hashcode = 133
        hashcode = hashcode * 23 + self.x_coordinate
        hashcode = hashcode * 23 + self.y_coordinate
        return hashcode

def __eq__(self, other):
    """ overriden equals method """
    if not other:
        return False
    else:
        return self.__cmp__(other) == 0

def __cmp__(self, other):
    """ overriden compare method """
    if other is not None:
        origin = Point(0.0, 0.0)
        if self.distance_between(origin) < other.distance_between(origin):
            return - 1
        elif self.distance_between(origin) > other.distance_between(origin):
        return 1
        else:
            return 0
def\uuuu散列(self,*args,**kwargs):
“”“重写哈希方法”“”
hashcode=133
hashcode=hashcode*23+self.x_坐标
hashcode=hashcode*23+self.y\u坐标
返回哈希码
定义(自身、其他):
“”“重写等于方法”“”
如果不是其他:
返回错误
其他:
返回self.\uuu cmp\uuuu(其他)=0
定义cmp(自身、其他):
“”“已重写比较方法”“”
如果“其他”不是“无”:
原点=点(0.0,0.0)
如果(原点)之间的自距离小于(原点)之间的其他距离:
返回-1
elif自身距离(原点)>其他距离(原点):
返回1
其他:
返回0

提前感谢…

您的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。尝试完全删除该函数,看看默认哈希函数是否更好

另外,您的
\uu cmp\uu
函数效率很低,因为每次比较它都会调用
distance\u-between
四次。尝试为每个
预计算该点与原点之间的距离,并将其存储在
对象中。然后,
\uuuu-cmp\uuuu
可以是这样的:

def __cmp__(self, other):
    return other.distance_to_origin - self.distance_to_origin

为什么不使用一个简单的
(x,y)
元组来表示您的积分呢?或者一个。它会快得多。

您考虑过使用阵列吗?numpy单个元素是统一的,而不是具有单个Python对象的开销。速度更快,内存效率更高

代码中至少有一个错误——可能不会导致性能问题,但值得指出。有一个要求
\uuuuu hash\uuuu()
方法必须满足以下条件:

唯一需要的属性是比较相等的对象具有相同的哈希值;建议以某种方式将对象组件的哈希值混合在一起(例如,使用异或),这些组件也在对象的比较中发挥作用

使用您的方法定义,两个比较相等的对象完全可能具有不同的哈希值。

对该代码的注释:

  • 由于您的方法有固定数量的参数(如
    def\uuu eq\uuuu(self,other):
    ),您不需要测试
    other
    是否为
    None
    ,只有在有可选参数时才需要这样做

  • 您的
    \uu\cmp\uu
    方法可疑。您没有显示
  • 之间的距离的定义,但暗示它是该点的距离;即,从x,y到原点0,0的距离。回想一下,第3,4点的欧几里德范数与第4,3点相同。即使点x=3和y=4与x=4和y=3是不同的点,它们是否确实意味着在程序逻辑中是相同的点

  • 你说每个地区有1000点。你说有70万分。由于每个区域有大约1000个点,因此必须有大约700个区域。为了简单起见,我将使用它,而不是复制
    区域

  • <>所以,考虑一下:

    import random
    import math
    
    size=100
    
    class Point(object):
        def __init__(self,x=0.0,y=0.0):
            self.x=x
            self.y=y
    
        def __hash__(self):
            t=(self.x,self.y)
            return hash(t)
    
        def __eq__(self, other):
            return self.__cmp__(other) == 0
    
        def distance_to_origin(self):
            return math.hypot(self.x,self.y)
    
        def __cmp__(self, other):
            return other.distance_to_origin() - self.distance_to_origin()
    
    look_up_table = {}
    for i in range(0,700):
        for j in range(0,1000):
            x=Point(random.uniform(-size,size),random.uniform(-size,size))
            look_up_table[x]=i
    
    print len(look_up_table), "hash points with ",size*2," range"
    
    示例代码基于其组成部分的元组实现了一个更快的
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
    。在我的机器上,这本词典是在3或4秒内完成的

    如上所述,您在
    \uuuu cmp\uuuu
    上的逻辑(我刚才简化了)可能有错误:

    x=Point(1.0,2.0)
    y=Point(1.0,2.0)
    z=Point(2.0,1.0)
    a=Point(2.2,1.1)
    
    print "x=y?", x==y    # as expected...
    print "x=a?", x==a    # also
    print "x=z?", x==z    # is that what you expect?
    
    即使
    点(1.0,2.0)=点(2.0,1.0)
    因为它们与
    点(0,0)
    的距离相同,
    散列(1.0,2.0)!=散列(2.0,1.0)
    。结果是,将有两个对象将相同的哈希值与不同的对象进行比较

    好吧,我是一个“迟到者”,所以:

    这里使用的
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuu散列
    \uuuuuuuuuuuueq
    的问题已被很好地涵盖。我想说,命名的tuple在这里的表现非常出色。下一个最快的收益(主要基于大小)将是使用
    \uuuuuu插槽
    。死givaway是指当您确定该点“仅”具有这两个属性时

    根据实际使用模式,我可能会:

  • 如果同时创建点和面域,请将“面域”属性添加到点。然后点“知道”它是“父项”…(例如,
    returnself.region
    in Point)
  • namedtuples应该可以加快解决这个大小问题的速度,但如果您需要扩展到更大的数字,您可以