按对象属性从列表中删除重复项的最佳方法

时间:2014-07-07 15:25:11

标签: python functional-programming

我有一个对象列表,我希望以一种方式过滤列表,结果每个属性值只出现一次。

例如,我们说我有三个对象

obj1.my_attr = 'a'
obj2.my_attr = 'b'
obj3.my_attr = 'b'

obj_list = [obj1, obj2, obj3]

最后,我想得到[obj1, obj2]。实际上顺序并不重要,所以[obj1, obj3]完全一样好。

首先,我想到了典型的强制性笨重方式:

record = set()
result = []

for obj in obj_list:
    if obj.my_attr not in record:
        record.add(obj.my_attr)
        result.append(obj)

然后我将它与maping一起用于字典,使用键覆盖任何先前的条目并最终提取值:

result = {obj.my_attr: obj for obj in obj_list}.values() 

这个看起来不错,但我想知道是否有更优雅,高效或功能性的方法来实现这一目标。也许隐藏在标准库中的一些甜蜜的东西......先谢谢。

3 个答案:

答案 0 :(得分:7)

如果要在Python中使用函数式编程样式,可能需要查看toolz包。使用toolz,您可以执行以下操作:

toolz.unique(obj_list, key=lambda x: x.my_attr)

为了获得更好的性能,您可以使用operator.attrgetter('my_attr')而不是lambda函数作为密钥。您也可以使用cytoolz,这是用Cython编写的toolz的快速实现。

答案 1 :(得分:3)

假设my_attr可以播放:

seen = set()
obj_list = [obj1, obj2, obj3]
new_obj_list = [x for x in obj_list if x.my_attr not in seen and not seen.add(x.my_attr)]

答案 2 :(得分:2)

您可以使用定义自定义__hash__函数的对象:

class HashMyAttr:
    def __init__(self, obj):
        self.obj = obj
    def __hash__(self):
        return self.obj.my_attr.__hash__()
    def __eq__(self, other):
         return self.obj.my_attr == other.obj.my_attr

并使用它:

obj_list = [x.obj for x in set(HashMyAttr(obj) for obj in obj_list)]