21

如果我有一个与 Python 集合的元素比较相等的对象,但不是同一个对象,是否有合理的方法来获取对集合中对象的引用?用例将使用该集合来识别和共享重复数据。

示例(Python 2.7):

>>> a = "This is a string"
>>> b = "This is a string"
>>> a is b
False
>>> a == b
True
>>> s = set((a,))
>>> b in s
True

如何获得a使用b和的参考s?我可以想到一种方法,但我不确定它是否不依赖于实现,无论你得到a还是b. 编辑:当 s 有多个元素时,这不起作用;交叉点很自然地实现了类似的东西[x for x in smaller_set if x in larger_set]

>>> for x in set((b,)).intersection(s): c = x
...
>>> c is a
True

也许一个好的解决方法是使用将每个键映射到自身的字典,而不是集合。

4

2 回答 2

5

我在 python-list 上发现了一个类似的问题:Get item from set参考get_equivalent(container, item) (Python recipe)有一个聪明的答案。

诀窍是为“key”对象构造一个包装器对象,并使用in运算符检查包装器是否在集合中。如果包装器哈希等于键,它的__eq__方法可以访问集合中的对象,并保存对它的引用。讨论中的一个重点是__eq__set 元素的方法必须返回无法识别的类型,否则可能不会调用NotImplemented包装器。__eq__

于 2011-12-29T20:32:41.120 回答
3

您的用例听起来像是字典的用例。将与“外来”对象比较的对象的属性用作键,并将所需对象本身用作值。

但是,如果它是一个简单的用例,并且您可以进行线性搜索,那么您可以做显而易见的事情-这还不错:

def get_equal(in_set, in_element):
   for element in in_set:
       if element == in_element:
           return element
   return None 

如果您需要您所要求的确切内容(我想知道一些用例)-要走的路是创建一个自定义字典类,该类具有一个集合作为其成员之一,请对成员集实现代理方法,并且在字典和集合方法中,保持字典和集合内容的同步。这将是耗时的实现正确,但相对简单,并且有 O(1) 时间。

如果必须复制对周围所有数据的引用不是问题(这是线性的,但可能比上面的直接搜索最差),您可以使用表达式

(data - (data - {key})).pop()

如:

In [40]: class A:
    ...:     def __init__(self, id, extra):
    ...:         self.id = id
    ...:         self.extra = extra
    ...:     def __eq__(self, other):
    ...:         return self.id == other.id
    ...:     def __hash__(self):
    ...:         return hash(self.id)
    ...:     def __repr__(self):
    ...:         return f"({self.id}, {self.extra})"
    ...: 
    ...: 

In [41]: data = set(A(i, "initial") for i in range(10))

In [42]: (data - (data - {A(5, None)})).pop()
Out[42]: (5, initial)
于 2011-12-23T13:39:19.057 回答