我有一组对象:
class Test(object):
def __init__(self):
self.i = random.randint(1,10)
res = set()
for i in range(0,1000):
res.add(Test())
print len(res) = 1000
如何从一组对象中删除重复项?
感谢您的回答,这是有效的:
class Test(object):
def __init__(self, i):
self.i = i
# self.i = random.randint(1,10)
# self.j = random.randint(1,20)
def __keys(self):
t = ()
for key in self.__dict__:
t = t + (self.__dict__[key],)
return t
def __eq__(self, other):
return isinstance(other, Test) and self.__keys() == other.__keys()
def __hash__(self):
return hash(self.__keys())
res = set()
res.add(Test(2))
...
res.add(Test(8))
结果:[2,8,3,4,5,6,7]
但如何保存订单?设置不支持订单。我可以使用列表代替设置吗?
答案 0 :(得分:11)
您的对象必须 hashable (即必须定义__eq__()
和__hash__()
)才能让套装正常使用:
class Test(object):
def __init__(self):
self.i = random.randint(1, 10)
def __eq__(self, other):
return self.i == other.i
def __hash__(self):
return self.i
如果对象具有在其生命周期内永远不会更改的哈希值(它需要
__hash__()
方法),并且可以与其他对象进行比较(它需要__eq__()
或{{ 1}}方法)。比较相等的Hashable对象必须具有相同的哈希值。Hashability使对象可用作字典键和set成员,因为这些数据结构在内部使用哈希值。
如果你有几个属性,哈希并比较它们的元组(谢谢,__cmp__()
):
delnan
答案 1 :(得分:1)
Pavel Anossov已经回答了你的第一个问题。
但你有另一个问题:
但如何保存订单?设置不支持订单。我可以使用列表代替设置吗?
你可以使用list
,但有一些缺点:
if foo not in res: res.append(foo)
。显然,你可以将它包装在一个函数中而不是重复编写它,但它仍然是额外的工作。您想要的是有序的set
。或者,等同于list
,不允许重复。
如果您先完成所有添加操作,然后执行所有查找操作,并且不需要快速查找,则可以首先构建list
,然后使用unique_everseen
来解决此问题。从itertools
recipes删除重复项。
或者您可以按顺序保留set
和list
或元素(或者到目前为止看到的list
加上set
个元素。但这可能会有点复杂,所以你可能想把它包起来。
理想情况下,您希望将其包装在与set
具有完全相同API的类型中。像OrderedSet
类似collections.OrderedDict
的东西。
幸运的是,如果你滚动到该文档页面的底部,你会看到你想要的确切存在;在ActiveState上有一个OrderedSet
食谱的链接。
因此,复制它,将其粘贴到您的代码中,然后只需将res = set()
更改为res = OrderedSet()
,就可以了。
答案 2 :(得分:0)
我认为,由于您定义了 eq 运算符,因此您可以轻松按照第一篇文章中的要求使用列表执行所需操作:
l = []
if Test(0) not in l :
l.append(Test(0))
我的2 cts ......
答案 3 :(得分:0)
Pavel Anossov的答案非常适合允许您的类在具有您想要的语义的集合中使用。但是,如果您想保留商品的订单,则需要更多。这是一个重复列表的函数,只要列表项是可清除的:
def dedupe(lst):
seen = set()
results = []
for item in lst:
if item not in seen:
seen.add(item)
results.append(item)
return results
稍微更惯用的版本是生成器,而不是返回列表的函数。这将使用results
删除yield
变量,而不是将唯一值附加到其中。我还将lst
参数重命名为iterable
,因为它在任何可迭代对象(例如另一个生成器)上都能正常工作。
def dedupe(iterable):
seen = set()
for item in iterable:
if item not in seen:
seen.add(item)
yield item