通过对象属性从列表中移除重复项的最佳方法

16 投票
2 回答
10578 浏览
提问于 2025-04-18 12:22

我有一个对象列表,我想把这个列表过滤一下,让每个属性值只出现一次。

比如说,我有三个对象:

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)

然后我想到了把它们放到一个字典里,用键来覆盖之前的条目,最后提取出值:

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

这个方法看起来不错,但我想知道有没有更优雅、更高效或者更函数式的做法。也许在标准库里有什么好东西隐藏着……提前谢谢大家。

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)]
11

如果你想在Python中使用函数式编程的风格,可以看看这个叫做 toolz 的包。使用 toolz,你可以很简单地做到:

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

为了提高性能,你可以用 operator.attrgetter('my_attr') 来替代用lambda函数作为关键字。你还可以使用 cytoolz,这是一个用Cython写的快速版本的 toolz

撰写回答