动态子集的Python高效查找结构?

动态子集的Python高效查找结构?,python,dictionary,set,immutability,Python,Dictionary,Set,Immutability,我试图对与某个给定集合的子集相关联的值进行常量时间查找,其中顺序是不保证的 我将积极处理原始集合,删除/添加回元素,并希望在继续操作时查找其余元素的关联值 例如,如果我的给定集是gived={1,2,3},那么我可能会构建一个如下所示的dict { frozenset([]): 'apple', frozenset([1]): 'orange', frozenset([2]): 'ice bear', frozenset([3]): 'peach', fr

我试图对与某个给定集合的子集相关联的值进行常量时间查找,其中顺序是不保证的

我将积极处理原始集合,删除/添加回元素,并希望在继续操作时查找其余元素的关联值

例如,如果我的给定集是
gived={1,2,3}
,那么我可能会构建一个如下所示的dict

{
    frozenset([]): 'apple',
    frozenset([1]): 'orange',
    frozenset([2]): 'ice bear',
    frozenset([3]): 'peach',
    frozenset([1, 2]): 'grizzly',
    frozenset([2, 3]): 'pear',
    frozenset([1, 3]): 'panda',
    frozenset([1, 2, 3]): 'banana',
}
假设我通过
gived.remove(2)
从给定集合中删除一个元素,留下
{1,3}
,我想查看关联的值。为了在dict中查找并检索值
“panda”
,我必须将我的集合强制为frozenset。因此,如果我通过
given.add(2)
添加回元素,恢复原始的
{1,2,3}
,那么在从dict中检索
banana
之前,我必须再次强制使用frozenset

我觉得强制使用冻结集是一个O(n)操作,它违背了O(1)查找的目的

有没有一种方法可以更有效地在Python中实现这种查找?或者这里有什么数据结构可以帮助我吗

我使用的是Py2.7,但如果Py3在这方面更好,请告诉我。谢谢

我觉得强制使用冻结集是一个O(n)操作,它违背了O(1)查找的目的

它在
给定的
的大小上是线性的,而不是在dict的大小上。为了进行比较,hash在
给定的
的大小上也是线性的,因此即使不必构造冻结集,也会有相同的渐近复杂性


如果此成本对您来说太高,您可以尝试使用允许增量更新的哈希函数编写自己的集合包装类,并打破可哈希对象不能以影响其哈希值的方式改变的通常条件。我个人在基于的方案中取得了很好的效果,其中集合的元素被分配了随机生成的哈希代码,该代码在程序的生命周期内一直存在,集合的哈希是所有元素哈希的XOR。添加或删除元素时,可以通过将其与元素的哈希进行异或来更新集合的哈希。

基于用户2357112的答案。没有经过测试,因为我失去了兴趣

from random import Random

class FastRehashableSet(set):
    _initial_hash = 12345

    def __init__(self, seq=()):
        super(FastRehashableSet, self).__init__(seq)
        self._hash = self._initial_hash
        for x in seq:
            self._hash_single_value(x)

    def _hash_single_value(self, val):
        # Introduce extra randomness since the intended elements are ints
        # which just return themselves when hashed
        self._hash ^= Random(hash(val)).randrange(4294967296)

    def __hash__(self):
        return self._hash

    def add(self, elem):
        super(FastRehashableSet, self).add(elem)
        self._hash_single_value(elem)

    def remove(self, elem):
        super(FastRehashableSet, self).remove(elem)
        self._hash_single_value(elem)

    def discard(self, elem):
        change = elem in self
        super(FastRehashableSet, self).discard(elem)
        if change:
            self._hash_single_value(elem)

    def pop(self):
        val = super(FastRehashableSet, self).pop()
        self._hash_single_value(val)
        return val

    def clear(self):
        super(FastRehashableSet, self).clear()
        self._hash = self._initial_hash

    # You get the idea, I'm not doing these

    def update(self):
        raise NotImplemented

    def intersection_update(self):
        raise NotImplemented

    def difference_update(self):
        raise NotImplemented

    def symmetric_difference_update(self):
        raise NotImplemented

如何从元素列表中以二进制形式对列表中的单词标记进行编码:

words = ["apple","orange","ice bear","peach","grizzly","panda","pear","banana"]

def get_indice(L):
    return sum(2**(i-1) for i in L)

# initial serie of elements
serie = [1,2,3]

# first computation of indice
ind = get_indice([1,2,3])

print serie,words[ind]

# remove the 2
val = 2
serie.remove(val)
ind -= 2**(val-1)

print serie,words[ind]

# add the 2
val = 2
serie.append(val)
serie = sorted(serie)
ind += 2**(val-1)

print serie,words[ind]
输出:

[1, 2, 3] banana
[1, 3] panda
[1, 2, 3] banana
请注意,第一次计算需要N次运算,其中N是级数中的元素数,这比单词中的元素数要好。以下添加和删除操作是直接的,成本为O(1)


因为去除意甲中的元素可能会花费一些费用。也许直接调用get_索引更好。

这是
O(n)
其中
n
是键集的大小,而不是字典的大小,这是一个重要的区别。这些电视机有多大?无论如何,在字典中查找仍然需要对键进行哈希运算,该键也必须是
O(n)
。谢谢Alex,这是绝对正确的。我想得不对。集合相当大,但理论上哈希本身也必须遍历键的长度。啊,是的。与键的大小成线性关系,而不是与单词的大小成线性关系。谢谢你,这很有意义。