# coding: utf-8
"""
brownie.datastructures.sets
~~~~~~~~~~~~~~~~~~~~~~~~~~~
:copyright: 2010-2011 by Daniel Neuhäuser
:license: BSD, see LICENSE.rst for details
"""
from functools import wraps
from brownie.itools import chain
from brownie.datastructures.mappings import OrderedDict
[docs]class OrderedSet(object):
"""
A :class:`set` which remembers insertion order.
.. versionadded:: 0.2
"""
def requires_set(func):
@wraps(func)
def wrapper(self, other):
if isinstance(other, (self.__class__, set, frozenset)):
return func(self, other)
return NotImplemented
return wrapper
def __init__(self, iterable=None):
self._orderedmap = OrderedDict.fromkeys(iterable or ())
def __len__(self):
return len(self._orderedmap)
def __contains__(self, element):
return element in self._orderedmap
def add(self, element):
self._orderedmap[element] = None
def remove(self, element):
del self._orderedmap[element]
def discard(self, element):
self._orderedmap.pop(element, None)
[docs] def pop(self, last=True):
"""
Returns the last element if `last` is ``True``, the first otherwise.
"""
if not self:
raise KeyError('set is empty')
element = self._orderedmap.popitem(last=last)[0]
return element
def clear(self):
self._orderedmap.clear()
def update(self, *others):
for other in others:
for element in other:
self._orderedmap[element] = None
def copy(self):
return self.__class__(self)
@requires_set
def __ior__(self, other):
self.update(other)
return self
def issubset(self, other):
return all(element in other for element in self)
@requires_set
def __le__(self, other):
return self.issubset(other)
@requires_set
def __lt__(self, other):
return self.issubset(other) and self != other
def issuperset(self, other):
return all(element in self for element in other)
@requires_set
def __ge__(self, other):
return self.issuperset(other)
@requires_set
def __gt__(self, other):
return self.issuperset(other) and self != other
def union(self, *others):
return self.__class__(chain.from_iterable((self, ) + others))
@requires_set
def __or__(self, other):
return self.union(other)
def intersection(self, *others):
def intersect(a, b):
result = self.__class__()
smallest = min([a, b], key=len)
for element in max([a, b], key=len):
if element in smallest:
result.add(element)
return result
return reduce(intersect, others, self)
@requires_set
def __and__(self, other):
return self.intersection(other)
@requires_set
def __iand__(self, other):
intersection = self.intersection(other)
self.clear()
self.update(intersection)
return self
def difference(self, *others):
return self.__class__(
key for key in self if not any(key in s for s in others)
)
@requires_set
def __sub__(self, other):
return self.difference(other)
@requires_set
def __isub__(self, other):
diff = self.difference(other)
self.clear()
self.update(diff)
return self
def symmetric_difference(self, other):
other = self.__class__(other)
return self.__class__(chain(self - other, other - self))
@requires_set
def __xor__(self, other):
return self.symmetric_difference(other)
@requires_set
def __ixor__(self, other):
diff = self.symmetric_difference(other)
self.clear()
self.update(diff)
return self
def __iter__(self):
return iter(self._orderedmap)
def __reversed__(self):
return reversed(self._orderedmap)
def __eq__(self, other):
if isinstance(other, self.__class__):
return len(self) == len(other) and list(self) == list(other)
return set(self) == other
def __ne__(self, other):
return not self.__eq__(other)
__hash__ = None
def __repr__(self):
content = repr(list(self)) if self else ''
return '%s(%s)' % (self.__class__.__name__, content)
del requires_set
__all__ = ['OrderedSet']