当两个列表都包含非集合时,找到两个列表交集的最有效方法是什么?
基本上,我们说我有以下列表(我已完全编写):
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))
...但很明显我无法使用set
或frozenset
作为非合并者,因为我得到了
TypeError: unhashable type: foo.bar
对于非合并者有没有这样的东西?
答案 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]
。