Python 从 set 中删除 set

根据我对 Python 2.7.2文档 内置类型5.7集合类型的解释,应该可以通过将 A 传递给 set.remove(elem)set.discard(elem)来从集合 B 中删除集合 A 的元素

来自2.7.2的文档:

注意,__contains__()remove()discard()的元素参数 方法可以是一个集合。

我将其解释为我可以将 set传递给 remove(elem)discard(elem),并且所有这些元素都将从目标集中删除。我会用这个来做一些奇怪的事情,比如删除字符串或 从词频直方图中删除所有常用词中的所有元音。测试代码如下:

Python 2.7.2 (default, Jun 12 2011, 14:24:46) [M...
Type "help", "copyright", "credits" or "license"
>>> a = set(range(10))
>>> b = set(range(5,10))
>>> a
set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> b
set([8, 9, 5, 6, 7])
>>> a.remove(b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: set([8, 9, 5, 6, 7])
>>> a.discard(b)
>>> a
set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>>

我希望你能还给我:

>>> a
set([0, 1, 2, 3, 4])

我知道我可以用返回一个新集的 a.difference(b),或者用 set.difference_update(other),或者用就地修改集的集合操作符 a -= b来实现这一点。

这是文档中的 bug 吗?set.remove(elem)真的不能把一个集合作为参数吗?还是文档引用了集合的集合?鉴于 difference_update完成了我的解释,我猜想情况是后者。

这还不够清楚吗?

剪辑 经过3年额外的(一些专业的) Python 工作,最近又回到了这个问题上,我现在意识到我实际上想做的事情可以通过以下方式来完成:

>>> c = a.difference(b)
set([0,1,2,3,4])

这正是我最初想要得到的。

剪辑 在 Python 开发的 还有四年之后... ... 我意识到这个操作可以使用集合文字和 -操作符更清晰地表示出来,并且更完整地表明集合差异是非交换的。

>>> a={0,1,2,3}
>>> b={2,3,4,5}
>>> a-b
set([0, 1])
>>> b-a
set([4, 5])
92904 次浏览

I think the documentation is referring to sets of (frozen)sets, yes.

You can't have sets of sets in Python as a set is mutable. Instead, you can have sets of frozensets. On the other hand, you can call __contains__(), remove(), and discard() with a set. See this example:

a = set([frozenset([2])])
set([2]) in a       # you get True
a.remove(set([2]))  # a is now empty

So the answer to your question is that the documentation is referring to sets of frozensets.

You already answered the question. It refers to sets of sets (actually sets containing frozensets).

The paragraph you are referring to begins with:

Note, the elem argument to the __contains__(), remove(), and discard() methods may be a set.

which means that b in a.remove(b) can be a set, and then continues with:

To support searching for an equivalent frozenset, the elem set is temporarily mutated during the search and then restored. During the search, the elem set should not be read or mutated since it does not have a meaningful value.

which means that if b is a set, a.remove(b) will scan a for a frozenset equivalent to b and remove it (or throw a KeyError if it doesn't exist).

I'm looking at the built-in help for various versions of python (for mac). Here are the results.

  • python2.5

remove(...)
Remove an element from a set; it must be a member.
If the element is not a member, raise a KeyError.

  • python2.6

remove(...)
Remove an element from a set; it must be a member. If the element is not a member, raise a KeyError.

  • python2.7

remove(...)
Remove an element from a set; it must be a member. If the element is not a member, raise a KeyError.

The documentation you refer to, in full, actually says:

Note, the elem argument to the __contains__(), remove(), and discard() methods may be a set. To support searching for an equivalent frozenset, the elem set is temporarily mutated during the search and then restored.

This seems to be a footnote, that suggests the argument may be a set, but unless it finds a matching frozen set within the set, it will not be removed. The mention about the set being modified is so it can be hashed to look for a a matching frozen set.

set1-set2

set1 = {0,1,2,3}
set2 = {2,3,4,5}


set1 - set2  # {0, 1}
set2 - set1  # {4, 5}

However, note that for whatever reason you can't "+" sets in python...