我知道如果我有两个整数列表,我可以简单地list(set(list1) & set(list2))
来得到交集。但是,在我的两个列表中,我有可变的对象,即Node
。 Node是可以使用值初始化的类。
无需执行双重for循环,是否有任何方法可以根据其ID获得两个列表的交集?我正在寻找类似于list(set(list1) & set(list2))
的东西。
更新:通过id,我指的是Python中内置的id()
函数,该函数返回对象在内存中存储的地址。
所以,我要问[Node1, Node2, Node3]
和[Node100, Node2, Node3]
的交集是什么。显然,我不能使用上面的设置交集方法。我需要通过访问内存来确定它们是相同的。如果我无法根据它们的value属性来识别它们,因为它们可能与Node1的值相同,但Node1可能具有与Node100相同的值,但是它们在内存中不是相同的对象。
答案 0 :(得分:3)
不需要相交两个集合。在这种情况下,您只需检查id()
是否在另一个集合中即可。
set2 = {id(n) for n in list2}
result = [n for n in list1 if id(n) in set2]
此代码的复杂度为O(n1 + n2)
。我将通过以下等效但可读性更高的代码对此进行解释:
set2 = {id(n) for n in list2} # O(n2)
result = []
for n in list1: # O(n1)
if id(n) in set2: # O(1)
result.append(n) # O(1)
总共是O(n1 + n2)
。
如果仅通过定义__hash__
和__eq__
方法就可以对Node
类进行更改,则还有另一种解决方案。
class Node:
...
def __hash__(self):
return id(self)
def __eq__(self, another):
return id(self) == id(another)
list1 = [...]
list2 = [...]
result = set(list1) & set(list2)
答案 1 :(得分:0)
您建议的解决方案将起作用。
class Node:
def __init__(self, value):
self.value = value
def __repr__(self):
return "Node {}".format(self.value)
nodes1 = [Node(1), Node(2), Node(3)]
nodes2 = nodes1[:2] + [Node(4)]
common_nodes = set(nodes1) & set(nodes2)
print(common_nodes) # {Node 2, Node 1}
之所以可行,是因为尽管它是可变的,但默认情况下,您尚未为其定义__hash__
或__eq__
的类的实例将被其id
进行散列和比较,因为它从object
继承了这些方法。
您可以通过以下实验确认这是真的。
>>> obj = object()
>>> hash(obj)
155115580943
>>> id(obj)
2481849295088
>>> id(obj) // 16 == hash(obj)
True