Jos*_*erg 10 python object set
我正在尝试创建一个在set操作中正常运行的自定义对象.
我一般都有它的工作,但我想确保我完全理解其含义.特别是,当对象中存在未包含在等于/哈希方法中的其他数据时,我对此行为感兴趣.似乎在'intersection'操作中,它返回正在进行比较的对象集,其中'union'操作返回正在比较的对象集.
为了显示:
class MyObject:
def __init__(self,value,meta):
self.value = value
self.meta = meta
def __eq__(self,other):
return self.value == other.value
def __hash__(self):
return hash(self.value)
a = MyObject('1','left')
b = MyObject('1','right')
c = MyObject('2','left')
d = MyObject('2','right')
e = MyObject('3','left')
print a == b # True
print a == c # False
for i in set([a,c,e]).intersection(set([b,d])):
print "%s %s" % (i.value,i.meta)
#returns:
#1 right
#2 right
for i in set([a,c,e]).union(set([b,d])):
print "%s %s" % (i.value,i.meta)
#returns:
#1 left
#3 left
#2 left
Run Code Online (Sandbox Code Playgroud)
这种行为是在某处记录并确定的吗?如果是这样,那么治理原则是什么?
不,这不是确定性的。问题是你破坏了 equals 和 hash 的不变量,即两个对象相等时是等价的。修复你的对象,不要试图变得聪明并滥用 set 的实现方式。如果元值是 MyObject 身份的一部分,则应将其包含在 eq 和 hash 中。
您不能依赖集合的交集来遵循任何顺序,因此无法轻松地执行您想要的操作。您最终要做的就是仅按值获取交集,然后在所有对象中查找旧对象来替换每个对象。没有好的方法可以通过算法来做到这一点。
工会并没有那么糟糕:
##fix the eq and hash to work correctly
class MyObject:
def __init__(self,value,meta):
self.value = value
self.meta = meta
def __eq__(self,other):
return self.value, self.meta == other.value, other.meta
def __hash__(self):
return hash((self.value, self.meta))
def __repr__(self):
return "%s %s" % (self.value,self.meta)
a = MyObject('1','left')
b = MyObject('1','right')
c = MyObject('2','left')
d = MyObject('2','right')
e = MyObject('3','left')
union = set([a,c,e]).union(set([b,d]))
print union
#set([2 left, 2 right, 1 left, 3 left, 1 right])
##sort the objects, so that older objs come before the newer equivalents
sl = sorted(union, key= lambda x: (x.value, x.meta) )
print sl
#[1 left, 1 right, 2 left, 2 right, 3 left]
import itertools
##group the objects by value, groupby needs the objs to be in order to do this
filtered = itertools.groupby(sl, lambda x: x.value)
##make a list of the oldest (first in group)
oldest = [ next(group) for key, group in filtered]
print oldest
#[1 left, 2 left, 3 left]
Run Code Online (Sandbox Code Playgroud)