gpt4 book ai didi

具有自定义哈希行为的 python 对象集

转载 作者:行者123 更新时间:2023-12-05 03:05:25 25 4
gpt4 key购买 nike

我想使用一个集合来管理“myItem”实例的集合。 myItem 类有自己的散列函数。这些项目的散列基于每个项目中的一些但不是全部数据,为简单起见,在下面的示例中,“数据”是字典 r。哈希考虑了 2 个键,hk1 和 hk2,并且在哈希计算中没有考虑第三个键“sad”。

class myItem():

def __init__(self, r):
# r is a dict holding information about the instance
# of course r has to have certain keys...
self.r = r

def __hash__(self):
"""Override the default hash behavior"""
return hash(tuple(sorted([self.r['hk1'],self.r['hk2']])))

def __eq__(self,other):
"""checking equality"""
if isinstance(other, self.__class__):
return self.__hash__() == other.__hash__()
return NotImplemented

def __ne__(self, other):
"""checking inequality"""
if isinstance(other, self.__class__):
return not self.__eq__(other)
return NotImplemented

def __repr__(self):
return str(self.r)

下面的简短单元测试确认了预期的行为。

class testMySet(unittest.TestCase):

def testMyItemstuff(self):

m1 = myItem({'hk1':'val1', 'hk2': 100, 'sad': 'other stuff'})
m2 = myItem({'hk1': 'val1', 'hk2': 100, 'sad': 'different other stuff'})

self.assertEqual(m1, m2)
self.assertNotEqual(m1.r['sad'], m2.r['sad'])

s = { m1 }
# add m2 to s
s.add(m2)
# same hash, m2 is not added
self.assertEqual(len(s), 1)
# set contains the original object, not the last one added
self.assertNotEqual(s.pop().r['sad'], 'different other stuff')

我的问题是,我该如何修改行为,以便添加一个哈希值与现有对象一致的新对象最终替换原始对象,同时对性能的影响最小?

最佳答案

以这种方式定义哈希值是否对您的应用程序有意义实际上由您来决定,但这似乎不太可能。

在任何情况下,我都可以想到两个与集合“一样快”的选项——O(1) 而不是 O(n)——它们的速度取决于实现你描述的哈希函数:

首先,归结类并创建实例:

class Item():
def __init__(self, a, b):
self.a = a
self.b = b

def __hash__(self):
return hash(self.a)

def __eq__(self,other):
if isinstance(other, self.__class__):
# Ignoring .b attribute
return self.a == other.a
else:
return NotImplemented

def __repr__(self):
return "Item(%s, %s)" % (self.a, self.b)

i1 = Item(1,2)
i2 = Item(3,4)
i3 = Item(1,5)


print(i1 == i2) # False (.a's don't match)
print(i1 == i3) # True (.a's match)

方法一:字典值

# Using a dict
updating_set = {}
updating_set[i1] = i1 # .values(): [Item(1, 2)]
updating_set[i2] = i2 # .values(): [Item(1, 2), Item(3, 4)]
updating_set[i3] = i3 # .values(): [Item(1, 5), Item(3, 4)]

print(list(updating_set.values()))
# [Item(1, 5), Item(3, 4)]

方法二:使用集合子类

# Using a set subclass
class UpdatingSet(set):
def add(self, item):
if item in self: super().remove(item)
super().add(item)

uset = UpdatingSet()
uset.add(i1) # UpdatingSet({Item(1, 2)})
uset.add(i2) # UpdatingSet({Item(1, 2), Item(3, 4)})
uset.add(i3) # UpdatingSet({Item(1, 5), Item(3, 4)})

奖励方法 3:不需要特殊的哈希函数

class NewItem():
def __init__(self, a, b):
self.a = a
self.b = b

def __repr__(self):
return "Item(%s, %s)" % (self.a, self.b)

class ItemSet():
def __init__(self):
self.items = {}

def add(self, item):
item_hash = item.a
self.items[item_hash] = item

def values(self):
return self.items.values()

i1 = NewItem(1,2)
i2 = NewItem(3,4)
i3 = NewItem(1,5)

iset = ItemSet()
iset.add(i1) # .values(): [Item(1, 2)]
iset.add(i2) # .values(): [Item(1, 2), Item(3, 4)]
iset.add(i3) # .values(): [Item(1, 5), Item(3, 4)]

print(list(iset.values())) # [Item(1, 5), Item(3, 4)]

这第三种方法不需要您实现hash(这可能会导致意想不到的副作用,但会模拟 ItemSet.add() 中的哈希过程,使用“哈希函数”作为字典键。

这可能是您最好的选择,除非您真的想要实现哈希并知道该决定的影响范围。

关于具有自定义哈希行为的 python 对象集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51014668/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com