2

当 Python 取两个集合的交集时,它总是从较小的集合返回元素,这在几乎所有情况下都是合理的,但我试图做相反的事情。

在下面的代码中,请注意交集产生一个整数,而不是浮点数。

[in]  >>> x = {1.0,2.0,3.0}
[in]  >>> y = {1}
[in]  >>> x.intersection(y)
[out] >>> {1}
[in]  >>> y.intersection(x)
[out] >>> {1}

如果我想得到一个浮点数,我必须使用一些繁重的复制。

[in]  >>> x - y
[out] >>> {2.0,3.0}
[in]  >>> x - (x - y)
[out] >>> {1.0}

我正在处理比上面的例子更大的集合。我的问题是是否有任何方法可以欺骗 Python set.intersection 方法从更大的集合中返回元素,或者除了我在这里所做的之外,是否还有另一种方法可以返回 float 1.0。

我首先这样做的原因是我试图通过对frozenset 进行子类化来在纯python 中实现一个冻结字典。我使用元组的子类存储键值对,我称之为“项目”,其中哈希仅返回键的哈希。使用下面的代码,我可以创建一个包含单个键值对的集合。然后我提取属性“值”并返回它。

def __getitem__(self, key):
    wrapped = Item((key,),flag=False)
    if not frozenset.__contains__(self, wrapped):
        raise KeyError(key)
    matches = self - (self - {wrapped})
    for pair in frozenset.__iter__(matches):
        return pair.value

我知道复制是缓慢的原因,因为当我尝试返回一个其键不在字典中的项目时,我立即得到一个 KeyError,即使对于具有 1000 万个项目的集合也是如此。

4

1 回答 1

1

冒着回答与您实际要求的不同的东西的风险(但可能有助于最终目标)...... Frozen dict 实际上容易在 python 中实现:

from collections import Mapping


class FrozenDict(Mapping):

    def __init__(self, *args, **kwargs):
        self._hash = None  # defer calculating hash until needed.
        self._data = dict(*args, **kwargs)

    def __getitem__(self, item):
        return self._data[item]

    def __len__(self):
        return len(self._data)

    def __iter__(self):
        return iter(self._dict)

    def __repr__(self):
        return '{}({!r})'.format(type(self), self._data)

    def __hash__(self):
        if self._hash is not None:
            return self._hash
        # Only hashible if the items are hashible.              
        self._hash = hash(tuple(self.items()))


x = FrozenDict({'a': 'b'})
print x
x['c'] = 'Bad Bad Bad'

当然,这并不是真正的冻结(与 freezeset 被冻结的意义相同)。用户可以访问并修改 freezeddict 上的数据——但是他们应该得到他们造成的任何代码破坏。


要回答您的实际问题,我能想到的唯一选择是定义您自己的交集函数:

>>> s1 = set([1])
>>> s2 = set([1., 2.])
>>> def intersection(s1, s2):
...     return set(x for x in s1 if x in s2)
... 
>>> intersection(s1, s2)
set([1])
>>> intersection(s2, s1)
set([1.0])

这个总是返回集合,但是如果你假设第一个输入的类型有一个只接受一个可迭代的构造函数,你可以很容易地修改为返回 freezeset 或输入的类型:

def intersection(s1, s2):
    output_type = type(s1)
    return output_type(x for x in s1 if x in s2)
于 2015-01-23T18:03:29.630 回答