请考虑以下代码:
>>> item1 = (1,)
>>> item2 = (2,)
>>> s = set([item1, item2])
>>> s
set([(2,), (1,)])
>>> new_item = (1,)
>>> new_item in s
True
>>> new_item == item1
True
>>> new_item is item1
False
所以new_item
位于s
中,因为它等同于其中一个项目,但它是一个不同的对象。
我想要的是item1
来自s
的{{1}} new_item
位于s
。
我提出的一个解决方案很简单,但效率不高:
def get_item(s, new_item):
for item in s:
if item == new_item:
return item
>>> get_item(s, new_item) is new_item
False
>>> get_item(s, new_item) is item1
True
另一种解决方案似乎更有效但实际上不起作用:
def get_item_using_intersection1(s, new_item):
return set([new_item]).intersection(s).pop()
也不是这个:
def get_item_using_intersection2(s, new_item):
return s.intersection(set([new_item])).pop()
因为交叉点以未定义的方式工作:
>>> get_item_using_intersection1(s, new_item) is new_item
True
>>> get_item_using_intersection1(s, new_item) is item1
False
>>> get_item_using_intersection2(s, new_item) is new_item
True
>>> get_item_using_intersection2(s, new_item) is item1
False
如果这很重要,我在Windows 7上使用Python 2.7 x64,但我需要一个跨平台的解决方案。
感谢大家。我提出了以下临时解决方案:
class SearchableSet(set):
def find(self, item):
for e in self:
if e == item:
return e
将来会用以下解决方案替换(现在非常不完整):
class SearchableSet(object):
def __init__(self, iterable=None):
self.__data = {}
if iterable is not None:
for e in iterable:
self.__data[e] = e
def __iter__(self):
return iter(self.__data)
def __len__(self):
return len(self.__data)
def __sub__(self, other):
return SearchableSet(set(self).__sub__(set(other)))
def add(self, item):
if not item in self:
self.__data[item] = item
def find(self, item):
return self.__data.get(item)
答案 0 :(得分:12)
然后不要使用set
。只需使用将某些值映射到自身的dict
即可。在您的情况下,它映射:
d[item1] = item1
d[item2] = item2
所以等于item1
的任何内容都会在d
中找到,但值本身为item1
。它比线性时间好得多; - )
P.S。我希望我能正确理解你的问题。如果没有,请澄清。
答案 1 :(得分:2)
如果您绝对需要O(1)查找和对象标识(不仅仅是相等)和快速设置操作(无需每次都需要创建新设置)要做集合操作),那么一个相当简单的方法是使用两个一个dict
和一个set
。您必须维护这两种结构以使它们保持同步,但这样可以保持O(1)访问(仅使用更大的常数因子)。 (也许这就是您在编辑中使用“现在非常不完整的未来解决方案”的目标。)
但是,您没有提到您正在使用的数据量,或者您遇到的性能问题,如果有的话。所以我不相信你真的需要这样做。可能是dict
创建了按需set
,或set
进行线性查找,已经足够快了。