包含非合并的2个列表的交集

时间:2016-08-27 21:39:28

标签: python

当两个列表都包含非集合时,找到两个列表交集的最有效方法是什么?

基本上,我们说我有以下列表(我已完全编写):

A = [<foo.bar object at 0x7f267c664080>, <foo.bar object at 0x7f267c664099>]
B = [<foo.bar object at 0x7f267c664080>, <foo.bar object at 0x123456789101>]

我们可以看到A的第一个元素与B的第一个元素相同。

我可以通过创建一个for循环来做一件简单的事情:

intersection = []

for obj_a in A:
    for obj_b in B:
        if ( (obj_a == obj_b) and (obj_a not in intersection) ):
            intersection.extend(obj_a)

但我只是想知道是否有更高效,更酷或更简单的方式。例如,有:

C = [1, 2, 3]
D = [3, 4, 5]
set(C).intersection(set(D))

...但很明显我无法使用setfrozenset作为非合并者,因为我得到了

TypeError: unhashable type: foo.bar

对于非合并者有没有这样的东西?

2 个答案:

答案 0 :(得分:1)

哈希是使set有效的原因。如果你不能散列,那么你就无法利用这种效率 - 你必须将每个对象与每个其他对象进行比较,你得到一个O(n²)算法而不是一个摊销的O(n)算法。

但是,如果您只关心对象身份而不是相等,那么您可以使用dicts将对象ID映射到对象,并获取ID的交集:

>>> class foo(object): pass
...
>>> f = foo()
>>> A = [foo(), foo(), f]
>>> B = [foo(), f, foo(), foo()]
>>> [a for a in A if id(a) in (set(map(id, A)) & set(map(id, B))]
[<__main__.foo object at 0x100a7e9d0>]

如果您想要一个更具代码效率的解决方案,或者您确实关心对象的相同性,那么@Neil's answer就足够了。

答案 1 :(得分:0)

使用列表推导的简单解决方案:intersection = [element for element in A if element in B检查是否存在相同的两个元素。例如,对于[1, 2, 3][0, 1, 5],它将返回[1]