class SortedListWithKey(MutableSequence): def __init__(self, iterable=None, key=lambda val: val, value_orderable=True, load=1000): self._key = key self._list = SortedList(load=load) self._ordered = value_orderable if value_orderable: self._pair = lambda key, value: (key, value) else: self._pair = Pair if iterable is not None: self.update(iterable) def clear(self): self._list.clear() def add(self, value): pair = self._pair(self._key(value), value) self._list.add(pair) def update(self, iterable): _key, _pair = self._key, self._pair self._list.update(_pair(_key(val), val) for val in iterable) def __contains__(self, value): _list = self._list _key = self._key(value) _pair = self._pair(_key, value) if self._ordered: return _pair in _list _maxes = _list._maxes if _maxes is None: return False pos = bisect_left(_maxes, _pair) if pos == len(_maxes): return False _lists = _list._lists idx = bisect_left(_lists[pos], _pair) len_lists = len(_lists) len_sublist = len(_lists[pos]) while True: pair = _lists[pos][idx] if _key != pair.key: return False if value == pair.value: return True idx += 1 if idx == len_sublist: pos += 1 if pos == len_lists: return False len_sublist = len(_lists[pos]) idx = 0 def discard(self, value): _list = self._list _key = self._key(value) _pair = self._pair(_key, value) if self._ordered: _list.discard(_pair) return _maxes = _list._maxes if _maxes is None: return pos = bisect_left(_maxes, _pair) if pos == len(_maxes): return _lists = _list._lists idx = bisect_left(_lists[pos], _pair) len_lists = len(_lists) len_sublist = len(_lists[pos]) while True: pair = _lists[pos][idx] if _key != pair.key: return if value == pair.value: _list._delete(pos, idx) return idx += 1 if idx == len_sublist: pos += 1 if pos == len_lists: return len_sublist = len(_lists[pos]) idx = 0 def remove(self, value): _list = self._list _key = self._key(value) _pair = self._pair(_key, value) if self._ordered: _list.remove(_pair) return _maxes = _list._maxes if _maxes is None: raise ValueError pos = bisect_left(_maxes, _pair) if pos == len(_maxes): raise ValueError _lists = _list._lists idx = bisect_left(_lists[pos], _pair) len_lists = len(_lists) len_sublist = len(_lists[pos]) while True: pair = _lists[pos][idx] if _key != pair.key: raise ValueError if value == pair.value: _list._delete(pos, idx) return idx += 1 if idx == len_sublist: pos += 1 if pos == len_lists: raise ValueError len_sublist = len(_lists[pos]) idx = 0 def __delitem__(self, index): del self._list[index] def __getitem__(self, index): if isinstance(index, slice): return list(tup[1] for tup in self._list[index]) else: return self._list[index][1] def __setitem__(self, index, value): _key, _pair = self._key, self._pair if isinstance(index, slice): self._list[index] = list(_pair(_key(val), val) for val in value) else: self._list[index] = _pair(_key(value), value) def __iter__(self): return iter(tup[1] for tup in iter(self._list)) def __reversed__(self): return iter(tup[1] for tup in reversed(self._list)) def __len__(self): return len(self._list) def bisect_left(self, value): pair = self._pair(self._key(value), value) return self._list.bisect_left(pair) def bisect(self, value): pair = self._pair(self._key(value), value) return self._list.bisect(pair) def bisect_right(self, value): pair = self._pair(self._key(value), value) return self._list.bisect_right(pair) def count(self, value): _list = self._list _key = self._key(value) _pair = self._pair(_key, value) if self._ordered: return _list.count(_pair) _maxes = _list._maxes if _maxes is None: return 0 pos = bisect_left(_maxes, _pair) if pos == len(_maxes): return 0 _lists = _list._lists idx = bisect_left(_lists[pos], _pair) total = 0 len_lists = len(_lists) len_sublist = len(_lists[pos]) while True: pair = _lists[pos][idx] if _key != pair.key: return total if value == pair.value: total += 1 idx += 1 if idx == len_sublist: pos += 1 if pos == len_lists: return total len_sublist = len(_lists[pos]) idx = 0 def copy(self): _key, _ordered, _load = self._key, self._ordered, self._list._load kwargs = dict(key=_key, value_orderable=_ordered, load=_load) return SortedListWithKey(self, **kwargs) def __copy__(self): return self.copy() def append(self, value): pair = self._pair(self._key(value), value) self._list.append(pair) def extend(self, iterable): _key, _pair = self._key, self._pair self._list.extend(_pair(_key(val), val) for val in iterable) def insert(self, index, value): pair = self._pair(self._key(value), value) self._list.insert(index, pair) def pop(self, index=-1): return self._list.pop(index)[1] def index(self, value, start=None, stop=None): _list = self._list _key = self._key(value) _pair = self._pair(_key, value) if self._ordered: return _list.index(_pair, start, stop) _len = _list._len if start == None: start = 0 if start < 0: start += _len if start < 0: start = 0 if stop == None: stop = _len if stop < 0: stop += _len if stop > _len: stop = _len if stop <= start: raise ValueError _maxes = _list._maxes pos = bisect_left(_maxes, _pair) if pos == len(_maxes): raise ValueError _lists = _list._lists idx = bisect_left(_lists[pos], _pair) len_lists = len(_lists) len_sublist = len(_lists[pos]) while True: pair = _lists[pos][idx] if _key != pair.key: raise ValueError if value == pair.value: loc = _list._loc(pos, idx) if start <= loc < stop: return loc idx += 1 if idx == len_sublist: pos += 1 if pos == len_lists: raise ValueError len_sublist = len(_lists[pos]) idx = 0 def as_list(self): return list(tup[1] for tup in self._list.as_list()) def __add__(self, that): result = SortedListWithKey( key=self._key, value_orderable=self._ordered, load=self._list._load) values = self.as_list() values.extend(that) result.update(values) return result def __iadd__(self, that): self.update(that) return self def __mul__(self, that): values = self.as_list() * that return SortedListWithKey( values, key=self._key, value_orderable=self._ordered, load=self._list._load) def __imul__(self, that): values = self.as_list() * that self.clear() self.update(values) return self def __eq__(self, that): return ((len(self) == len(that)) and all(lhs == rhs for lhs, rhs in zip(self, that))) def __ne__(self, that): return ((len(self) != len(that)) or any(lhs != rhs for lhs, rhs in zip(self, that))) def __lt__(self, that): return ((len(self) <= len(that)) and all(lhs < rhs for lhs, rhs in zip(self, that))) def __le__(self, that): return ((len(self) <= len(that)) and all(lhs <= rhs for lhs, rhs in zip(self, that))) def __gt__(self, that): return ((len(self) >= len(that)) and all(lhs > rhs for lhs, rhs in zip(self, that))) def __ge__(self, that): return ((len(self) >= len(that)) and all(lhs >= rhs for lhs, rhs in zip(self, that))) @recursive_repr def __repr__(self): return '%s(%s, key=%r, value_orderable=%r, load=%r)' % ( self.__class__.__name__, self.as_list(), self._key, self._ordered, self._list._load)
class SortedDict(MutableMapping): """ A SortedDict provides the same methods as a dict. Additionally, a SortedDict efficiently maintains its keys in sorted order. Consequently, the keys method will return the keys in sorted order, the popitem method will remove the item with the highest key, etc. """ def __init__(self, *args, **kwargs): if len(args) > 0 and type(args[0]) == int: load = args[0] args = args[1:] else: load = 1000 self._dict = dict() self._list = SortedList(load=load) self.iloc = _IlocWrapper(self) self.update(*args, **kwargs) def clear(self): self._dict.clear() self._list.clear() def __contains__(self, key): return key in self._dict def __delitem__(self, key): del self._dict[key] self._list.remove(key) def __getitem__(self, key): return self._dict[key] def __eq__(self, that): return (len(self._dict) == len(that) and all((key in that) and (self[key] == that[key]) for key in self)) def __ne__(self, that): return (len(self._dict) != len(that) or any((key not in that) or (self[key] != that[key]) for key in self)) def __iter__(self): return iter(self._list) def __reversed__(self): return reversed(self._list) def __len__(self): return len(self._dict) def __setitem__(self, key, value): _dict = self._dict if key not in _dict: self._list.add(key) _dict[key] = value def copy(self): return SortedDict(self._list._load, self._dict) def __copy__(self): return self.copy() @classmethod def fromkeys(cls, seq, value=None): that = SortedDict((key, value) for key in seq) return that def get(self, key, default=None): return self._dict.get(key, default) def has_key(self, key): return key in self._dict def items(self): return list(self.iteritems()) def iteritems(self): _dict = self._dict return iter((key, _dict[key]) for key in self._list) def keys(self): return SortedSet(self._dict) def iterkeys(self): return iter(self._list) def values(self): return list(self.itervalues()) def itervalues(self): _dict = self._dict return iter(_dict[key] for key in self._list) def pop(self, key, default=_NotGiven): if key in self._dict: self._list.remove(key) return self._dict.pop(key) else: if default == _NotGiven: raise KeyError else: return default def popitem(self): _dict, _list = self._dict, self._list if len(_dict) == 0: raise KeyError key = _list.pop() value = _dict[key] del _dict[key] return (key, value) def setdefault(self, key, default=None): _dict = self._dict if key in _dict: return _dict[key] else: _dict[key] = default self._list.add(key) return default def update(self, *args, **kwargs): _dict, _list = self._dict, self._list if len(_dict) == 0: _dict.update(*args, **kwargs) _list.update(_dict) return if (len(kwargs) == 0 and len(args) == 1 and isinstance(args[0], dict)): pairs = args[0] else: pairs = dict(*args, **kwargs) if (10 * len(pairs)) > len(self._dict): self._dict.update(pairs) _list = self._list _list.clear() _list.update(self._dict) else: for key in pairs: self[key] = pairs[key] def index(self, key, start=None, stop=None): return self._list.index(key, start, stop) def bisect_left(self, key): return self._list.bisect_left(key) def bisect(self, key): return self._list.bisect(key) def bisect_right(self, key): return self._list.bisect_right(key) @not26 def viewkeys(self): return KeysView(self) @not26 def viewvalues(self): return ValuesView(self) @not26 def viewitems(self): return ItemsView(self) @recursive_repr def __repr__(self): _dict = self._dict return '%s({%s})' % ( self.__class__.__name__, ', '.join('%r: %r' % (key, _dict[key]) for key in self._list))
class SortedDict(MutableMapping): """ A SortedDict provides the same methods as a dict. Additionally, a SortedDict efficiently maintains its keys in sorted order. Consequently, the keys method will return the keys in sorted order, the popitem method will remove the item with the highest key, etc. """ def __init__(self, *args, **kwargs): if len(args) > 0 and type(args[0]) == int: load = args[0] args = args[1:] else: load = 1000 self._dict = dict() self._list = SortedList(load=load) self.iloc = _IlocWrapper(self) self.update(*args, **kwargs) def clear(self): self._dict.clear() self._list.clear() def __contains__(self, key): return key in self._dict def __delitem__(self, key): del self._dict[key] self._list.remove(key) def __getitem__(self, key): return self._dict[key] def __eq__(self, that): return (len(self._dict) == len(that) and all( (key in that) and (self[key] == that[key]) for key in self)) def __ne__(self, that): return (len(self._dict) != len(that) or any( (key not in that) or (self[key] != that[key]) for key in self)) def __iter__(self): return iter(self._list) def __reversed__(self): return reversed(self._list) def __len__(self): return len(self._dict) def __setitem__(self, key, value): _dict = self._dict if key not in _dict: self._list.add(key) _dict[key] = value def copy(self): return SortedDict(self._list._load, self._dict) def __copy__(self): return self.copy() @classmethod def fromkeys(cls, seq, value=None): that = SortedDict((key, value) for key in seq) return that def get(self, key, default=None): return self._dict.get(key, default) def has_key(self, key): return key in self._dict def items(self): return list(self.iteritems()) def iteritems(self): _dict = self._dict return iter((key, _dict[key]) for key in self._list) def keys(self): return SortedSet(self._dict) def iterkeys(self): return iter(self._list) def values(self): return list(self.itervalues()) def itervalues(self): _dict = self._dict return iter(_dict[key] for key in self._list) def pop(self, key, default=_NotGiven): if key in self._dict: self._list.remove(key) return self._dict.pop(key) else: if default == _NotGiven: raise KeyError else: return default def popitem(self): _dict, _list = self._dict, self._list if len(_dict) == 0: raise KeyError key = _list.pop() value = _dict[key] del _dict[key] return (key, value) def setdefault(self, key, default=None): _dict = self._dict if key in _dict: return _dict[key] else: _dict[key] = default self._list.add(key) return default def update(self, *args, **kwargs): _dict, _list = self._dict, self._list if len(_dict) == 0: _dict.update(*args, **kwargs) _list.update(_dict) return if (len(kwargs) == 0 and len(args) == 1 and isinstance(args[0], dict)): pairs = args[0] else: pairs = dict(*args, **kwargs) if (10 * len(pairs)) > len(self._dict): self._dict.update(pairs) _list = self._list _list.clear() _list.update(self._dict) else: for key in pairs: self[key] = pairs[key] def index(self, key, start=None, stop=None): return self._list.index(key, start, stop) def bisect_left(self, key): return self._list.bisect_left(key) def bisect(self, key): return self._list.bisect(key) def bisect_right(self, key): return self._list.bisect_right(key) @not26 def viewkeys(self): return KeysView(self) @not26 def viewvalues(self): return ValuesView(self) @not26 def viewitems(self): return ItemsView(self) @recursive_repr def __repr__(self): _dict = self._dict return '%s({%s})' % (self.__class__.__name__, ', '.join( '%r: %r' % (key, _dict[key]) for key in self._list))
class SortedSet(MutableSet, Sequence): """ A `SortedSet` provides the same methods as a `set`. Additionally, a `SortedSet` maintains its items in sorted order, allowing the `SortedSet` to be indexed. Unlike a `set`, a `SortedSet` requires items be hashable and comparable. """ def __init__(self, iterable=None, load=1000, _set=None): if _set is None: self._set = set() else: self._set = set self._list = SortedList(self._set, load=load) if iterable is not None: self.update(iterable) def __contains__(self, value): return (value in self._set) def __getitem__(self, index): if isinstance(index, slice): return SortedSet(self._list[index]) else: return self._list[index] def __delitem__(self, index): _list = self._list if isinstance(index, slice): values = _list[index] self._set.difference_update(values) else: value = _list[index] self._set.remove(value) del _list[index] def __setitem__(self, index, value): _list, _set = self._list, self._set prev = _list[index] _list[index] = value if isinstance(index, slice): _set.difference_update(prev) _set.update(prev) else: _set.remove(prev) _set.add(prev) def __eq__(self, that): if len(self) != len(that): return False if isinstance(that, SortedSet): return (self._list == that._list) elif isinstance(that, set): return (self._set == that) else: _set = self._set return all(val in _set for val in that) def __ne__(self, that): if len(self) != len(that): return True if isinstance(that, SortedSet): return (self._list != that._list) elif isinstance(that, set): return (self._set != that) else: _set = self._set return any(val not in _set for val in that) def __lt__(self, that): if isinstance(that, set): return (self._set < that) else: return (len(self) < len(that)) and all(val in that for val in self._list) def __gt__(self, that): if isinstance(that, set): return (self._set > that) else: _set = self._set return (len(self) > len(that)) and all(val in _set for val in that) def __le__(self, that): if isinstance(that, set): return (self._set <= that) else: return all(val in that for val in self._list) def __ge__(self, that): if isinstance(that, set): return (self._set >= that) else: _set = self._set return all(val in _set for val in that) def __and__(self, that): return self.intersection(that) def __or__(self, that): return self.union(that) def __sub__(self, that): return self.difference(that) def __xor__(self, that): return self.symmetric_difference(that) def __iter__(self): return iter(self._list) def __len__(self): return len(self._set) def __reversed__(self): return reversed(self._list) def add(self, value): if value not in self._set: self._set.add(value) self._list.add(value) def bisect_left(self, value): return self._list.bisect_left(value) def bisect(self, value): return self._list.bisect(value) def bisect_right(self, value): return self._list.bisect_right(value) def clear(self): self._set.clear() self._list.clear() def copy(self): return SortedSet(load=self._list._load, _set=set(self._set)) def __copy__(self): return self.copy() def count(self, value): return int(value in self._set) def discard(self, value): if value in self._set: self._set.remove(value) self._list.discard(value) def index(self, value, start=None, stop=None): return self._list.index(value, start, stop) def isdisjoint(self, that): return self._set.isdisjoint(that) def issubset(self, that): return self._set.issubset(that) def issuperset(self, that): return self._set.issuperset(that) def pop(self, index=-1): value = self._list.pop(index) self._set.remove(value) return value def remove(self, value): self._set.remove(value) self._list.remove(value) def difference(self, *iterables): diff = self._set.difference(*iterables) new_set = SortedSet(load=self._list._load, _set=diff) return new_set def difference_update(self, *iterables): values = set(chain(*iterables)) if (4 * len(values)) > len(self): self._set.difference_update(values) self._list.clear() self._list.update(self._set) else: _discard = self.discard for value in values: _discard(value) def intersection(self, *iterables): comb = self._set.intersection(*iterables) new_set = SortedSet(load=self._list._load, _set=comb) return new_set def intersection_update(self, *iterables): self._set.intersection_update(*iterables) self._list.clear() self._list.update(self._set) def symmetric_difference(self, that): diff = self._set.symmetric_difference(that) new_set = SortedSet(load=self._list._load, _set=diff) return new_set def symmetric_difference_update(self, that): self._set.symmetric_difference_update(that) self._list.clear() self._list.update(self._set) def union(self, *iterables): return SortedSet(chain(iter(self), *iterables), load=self._list._load) def update(self, *iterables): values = set(chain(*iterables)) if (4 * len(values)) > len(self): self._set.update(values) self._list.clear() self._list.update(self._set) else: _add = self.add for value in values: _add(value) @recursive_repr def __repr__(self): return '%s(%r)' % (self.__class__.__name__, list(self))