Python自定义集合交集

Ben*_*ott 5 python python-2.x set-intersection

因此,存在一种通过set.intersection()计算两个集合的交集的简单方法.但是,我有以下问题:

class Person(Object):                    
    def __init__(self, name, age):                                                      
        self.name = name                                                                
        self.age = age                                                                  

l1 = [Person("Foo", 21), Person("Bar", 22)]                                             
l2 = [Person("Foo", 21), Person("Bar", 24)]                                             

union_list = list(set(l1).union(l2))                                           
# [Person("Foo", 21), Person("Bar", 22), Person("Bar", 24)]
Run Code Online (Sandbox Code Playgroud)

(Object是我的ORM提供的基类,它实现了基本__hash____eq__功能,它基本上将类的每个成员添加到哈希.换句话说,__hash__返回的将是类的每个元素的哈希)

在这个阶段,我想只运行一个集合交叉运算.name,比如说Person('Bar', -1).intersection(union_list) #= [Person("Bar", -1), Person("Bar", 22), Person("Bar", 24)].(典型的.intersection()在这一点上不会给我什么,我不能重写__hash__或者__eq__Person类,因为这会覆盖原有的并集(我认为)

在Python 2.x中执行此操作的最佳方法是什么?

编辑:请注意,该解决方案不具有依靠set.但是,我需要找到工会然后交叉点,所以感觉这对于一套是合适的(但我愿意接受使用你认为值得的任何魔法的解决方案,只要它能解决我的问题!)

Jon*_*röm 6

听起来好像

>>> class Person:
...     def __init__(self, name, age):
...         self.name = name
...         self.age = age
...     def __eq__(self, other):
...         return self.name == other.name
...     def __hash__(self):
...         return hash(self.name)
...     def __str__(self):
...         return self.name
...
>>> l1 = [Person("Foo", 21), Person("Bar", 22)]
>>> l2 = [Person("Foo", 21), Person("Bar", 24)]
>>> union_list = list(set(l1).union(l2))
>>> [str(l) for l in union_list]
['Foo', 'Bar']
Run Code Online (Sandbox Code Playgroud)

是你想要的,因为name你的独特钥匙?


Ben*_*ott 2

我讨厌回答自己的问题,所以我会暂时推迟将其标记为“答案”。

事实证明,这样做的方法如下:

import types
p = Person("Bar", -1)
new_hash_method = lambda obj: hash(obj.name)
p.__hash__ = types.MethodType(new_hash_method, p)
for i in xrange(0, len(union_list)):
    union_list[i].__hash__ = types.MethodType(new_hash_method, union_list[i])
set(union_list).intersection(p)
Run Code Online (Sandbox Code Playgroud)

它当然很脏并且依赖于types.MethodType,但它比迄今为止提出的最佳解决方案(glglgl 的解决方案)强度要低,因为我的实际union_list可能包含数千个项目,因此这将节省我每次运行时重新创建对象的麻烦这个交叉过程。