我有一个对象列表,我希望以一种方式过滤列表,结果每个属性值只出现一次。
例如,我们说我有三个对象
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()
这个看起来不错,但我想知道是否有更优雅,高效或功能性的方法来实现这一目标。也许隐藏在标准库中的一些甜蜜的东西......先谢谢。
答案 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)]