setutils - IndexedSet 类型

这个 set 类型将集合论的实际表现力带到了Python中。它总体上有一个非常丰富的API,但缺乏几个基本功能。首先,套餐是不订购的。最重要的是,集合是不可索引的,即, my_set[8] 将引发一个 TypeError 。这个 IndexedSet 类型解决了这两个问题,而不会影响到Python的内置Set实现的优秀复杂性特征。

class boltons.setutils.IndexedSet(other=None)[源代码]

IndexedSet 是一种 collections.MutableSet 以保持插入元素的插入顺序和唯一性。它是一种混合类型,主要类似于OrderedSet,但也 list -Like,因为它支持索引和切片。

参数:

other (iterable) -- 用于初始化集的可选迭代器。

>>> x = IndexedSet(list(range(4)) + list(range(8)))
>>> x
IndexedSet([0, 1, 2, 3, 4, 5, 6, 7])
>>> x - set(range(2))
IndexedSet([2, 3, 4, 5, 6, 7])
>>> x[-1]
7
>>> fcr = IndexedSet('freecreditreport.com')
>>> ''.join(fcr[:fcr.index('.')])
'frecditpo'

标准集运算符与互操作 set 均受支持:

>>> fcr & set('cash4gold.com')
IndexedSet(['c', 'd', 'o', '.', 'm'])

如您所见, IndexedSet 几乎就像是一个 UniqueList ,只保留给定值的一个副本,按其第一次添加的顺序。对于好奇的人来说,IndexedSet不支持基于索引设置项的原因(即, __setitem__() ),考虑以下两难境地:

my_indexed_set = [A, B, C, D]
my_indexed_set[2] = A

在这一点上,一个集合只需要一个 A ,而是一个 list 将覆盖 C 。覆盖 C 会改变列表的长度,这意味着 my_indexed_set[2] 不会是 A ,与预期的列表一样,但更确切地说 D 。所以,不 __setitem__()

否则,API将努力成为 listset 尽可能多地使用API。

add(item) add item to the set[源代码]
clear() empty the set[源代码]
count(val) -> count number of instances of value (0 or 1)[源代码]
difference(*others) get a new set with elements not in others[源代码]
difference_update(*others) -> discard self.intersection(*others)[源代码]
discard(item) -> discard item from the set (does not raise)[源代码]
classmethod from_iterable(it) create a set from an iterable[源代码]
index(val) get the index of a value, raises if not present[源代码]
intersection(*others) get a set with overlap of this and others[源代码]
intersection_update(*others) -> discard self.difference(*others)[源代码]
isdisjoint(other) return True if no overlap with other[源代码]
issubset(other) return True if other contains this set[源代码]
issuperset(other) return True if set contains other[源代码]
iter_difference(*others) iterate over elements not in others[源代码]
iter_intersection(*others) iterate over elements also in others[源代码]
iter_slice(start, stop, step=None)[源代码]

遍历集合的一片

pop(index) -> remove the item at a given index (-1 by default)[源代码]
remove(item) remove item from the set, raises if not present[源代码]
reverse() reverse the contents of the set in-place[源代码]
sort() sort the contents of the set in-place[源代码]
symmetric_difference(*others) XOR set of this and others[源代码]
symmetric_difference_update(other) in-place XOR with other[源代码]
union(*others) return a new set containing this set and others[源代码]
update(*others) add values from one or more iterables[源代码]
boltons.setutils.complement(wrapped)[源代码]

给出了一个 set ,将其转换为 complement set

鉴于A set 跟踪它包含的内容,一个 complement set 跟踪它做了什么 not 包围圈。例如,看看当我们将正常集与补集相交时会发生什么:

>>> list(set(range(5)) & complement(set([2, 3])))

[0, 1, 4]

我们得到左边不在右边的所有东西,因为与补码相交等同于减去一个正常集。

参数:

wrapped (set) -- 应变为补集的集合或任何其它可迭代的集合。

所有集合方法和运算符都受补集支持,在其他 complement() -套装和/或常规套装 set 物体。

因为补集只跟踪元素是什么 not 在SET中,基于SET内容的功能不可用: len()iter() (和循环),以及 .pop() 。但补集总是可以通过再次补集来变回常规集:

>>> s = set(range(5))
>>> complement(complement(s)) == s
True

备注

空的补集对应于 universal set 来自数学。

举例说明补集

集合的许多用法可以通过补语更简单地表示出来。你不需要在脑子里想出正确的方法来颠倒一个表达,你只需在集合中抛出一个补语即可。考虑以下名称筛选器的示例:

>>> class NamesFilter(object):
...    def __init__(self, allowed):
...        self._allowed = allowed
...
...    def filter(self, names):
...        return [name for name in names if name in self._allowed]
>>> NamesFilter(set(['alice', 'bob'])).filter(['alice', 'bob', 'carol'])
['alice', 'bob']

如果我们只是想表达“让所有的名字都通过”呢?

我们可以尝试列举所有预期的名称::

``NamesFilter({'alice', 'bob', 'carol'})``

但这是非常脆弱的--如果在某个点上将此对象更改为滤镜怎么办 ['alice', 'bob', 'carol', 'dan']

更糟糕的是,接下来处理这段代码的可怜的程序员怎么办?他们不知道这个庞大的允许集的目的是“允许一切”,还是因为某种微妙的原因而将“Dan”排除在外。

补语集让程序员的意图被简洁而直接地表达出来:

NamesFilter(complement(set()))

这段代码不仅简短且健壮,而且其意图也很容易理解。