Python 如何按属性从iterable中删除所有重复项?

Python 如何按属性从iterable中删除所有重复项?,python,set,Python,Set,给定一个可数,例如 results = [ref_a, # references big object A ref_b, # references big object B ref_c, # references big object A ref_d, # references big object D ] 每个引用都是唯一的对象,但有些引用相同(更大)的对象 我只想要一组(或列表)唯一对象的引用 我期望的结果是 custom_

给定一个可数,例如

results = [ref_a, # references big object A
           ref_b, # references big object B
           ref_c, # references big object A
           ref_d, # references big object D
]
每个引用都是唯一的对象,但有些引用相同(更大)的对象

我只想要一组(或列表)唯一对象的引用

我期望的结果是

custom_set = (ref_a,
              ref_b,
              ref_d,
)
备注

Python内置
不适用,因为来自输入的对象都不同。这意味着
set
将返回所有元素

我无法更改引用的类定义,因此无法实现自定义cmp/哈希函数或类似函数

最终结果是否包含
ref\u a
ref\u c
并不重要

最初的结果是不同API的结果的组合,这些API独立运行-这也是组合列表可以引用相同(大)对象的原因

我无法存储
结果。仅参考
,因为在过滤之后,我需要访问
结果的其他属性
。如果我只存储
result.reference
,我将不得不实例化昂贵的对象

很抱歉使用
result
作为输入参数,但我不想在以后更改它,因为答案将不再适合该问题。我将记住这一点,以便将来提问


也许
reference
也不是最好的命名方法-它更像是一个轻量级代理对象。

我想出了这个解决方案,但肯定有更好/更具python风格的解决方案

known = set()
custom_set = set()
for result in results:
    if result.reference not in known:
       known.add(result.reference)
       custom_set.add(result)

我提出了这个解决方案,但肯定有更好的/更符合Python的解决方案

known = set()
custom_set = set()
for result in results:
    if result.reference not in known:
       known.add(result.reference)
       custom_set.add(result)

虽然您可以使用
itertools.groupby
解决此问题,但您的代码很好

from itertools import groupby
from operator import attrgetter

f = attrgetter('reference')
custom_set = set(next(x) for _, x in groupby(sorted(results, key=f), f))
排序的
groupby
都是稳定的,因此
next(x)
保证是
结果中的第一个元素,具有
reference
属性的特定值

这种方法的一个缺点是,与列表的O(n)遍历相比,
sorted()
需要O(n lgn)时间

您也可以将代码编写为(主要是)一行程序,尽管我不建议这样做:

known = {}
custom_set = set(known.add(r.reference) and r for r in result if r.reference not in known)

known.add(r.reference)
将始终返回
None
,因此
表达式的值将始终是
r
,但表达式本身只有在
r.reference
不在
known
中时才会计算。
表达式只是一种处理将
已知
更新到生成器表达式中的副作用的方法。

您的代码很好,尽管您可以使用
itertools.groupby
解决此问题

from itertools import groupby
from operator import attrgetter

f = attrgetter('reference')
custom_set = set(next(x) for _, x in groupby(sorted(results, key=f), f))
排序的
groupby
都是稳定的,因此
next(x)
保证是
结果中的第一个元素,具有
reference
属性的特定值

这种方法的一个缺点是,与列表的O(n)遍历相比,
sorted()
需要O(n lgn)时间

您也可以将代码编写为(主要是)一行程序,尽管我不建议这样做:

known = {}
custom_set = set(known.add(r.reference) and r for r in result if r.reference not in known)
known.add(r.reference)
将始终返回
None
,因此
表达式的值将始终是
r
,但表达式本身只有在
r.reference
不在
known
中时才会计算。
表达式只是处理将
已知
更新到生成器表达式中的副作用的一种方法。

试试这个

a=[]

for i in results:

    if i not in a:

        a.append(i)

print(a)
试试这个

a=[]

for i in results:

    if i not in a:

        a.append(i)

print(a)

你能给出一个更具体的例子吗?每个参考变量的值都会很有帮助。现在我看不出我在做什么。我还想补充一点,你在这里的处境很危险,因为你的问题有不止一个有效的解决方案。。也许可以考虑存储参考文献。EV/恩里克——你是对的——我试图改进我的问题——我希望现在更清楚。但是,很难想出一个更具体的例子,因为它实际上是关于轻量级代理对象的,它为更昂贵的对象保留了一个引用。对于后者,我试图阻止实例化。你能给出一个更具体的例子吗?每个ref-var的值都会很有帮助。现在我看不出我在做什么。我还想补充一点,你在这里的处境很危险,因为你的问题有不止一个有效的解决方案。。也许可以考虑存储参考文献。EV/恩里克——你是对的——我试图改进我的问题——我希望现在更清楚。但是,很难想出一个更具体的例子,因为它实际上是关于轻量级代理对象的,它为更昂贵的对象保留了一个引用。对于后者,我试图阻止实例化。Monu,谢谢你的回答。不幸的是,它不适用于这个问题。结果/引用都是不同的对象,但有一个公共属性值(result.reference)。用你的代码,没有一个对象会被过滤掉。它更像是完整列表的副本。正如其他人指出的,我应该改进我的问题。莫努,谢谢你的回答。不幸的是,它不适用于这个问题。结果/引用都是不同的对象,但有一个公共属性值(result.reference)。用你的代码,没有一个对象会被过滤掉。它更像是完整列表的副本。正如其他人指出的,我应该改进我的问题。切普纳,非常感谢你的解决方案。我花了太多时间在非常古老的Python代码库中,我当然猜到有一些解决方案涉及itertools/set或dict理解,但我个人认为这两种解决方案都很难阅读。也许只是我,因为我不习惯这种解决方案。无论如何,非常感谢你!切普纳,非常感谢你的解决方案。我花了太多时间在非常古老的Python代码库中,我当然猜有一些解决方案涉及itertools/set或dict compre