v1.3.5
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
"""Python Sorted Collections
|
||||
|
||||
SortedCollections is an Apache2 licensed Python sorted collections library.
|
||||
|
||||
>>> from sortedcollections import ValueSortedDict
|
||||
>>> vsd = ValueSortedDict({'a': 2, 'b': 1, 'c': 3})
|
||||
>>> list(vsd.keys())
|
||||
['b', 'a', 'c']
|
||||
|
||||
:copyright: (c) 2015-2021 by Grant Jenks.
|
||||
:license: Apache 2.0, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
|
||||
from sortedcontainers import (
|
||||
SortedDict,
|
||||
SortedList,
|
||||
SortedListWithKey,
|
||||
SortedSet,
|
||||
)
|
||||
|
||||
from .nearestdict import NearestDict
|
||||
from .ordereddict import OrderedDict
|
||||
from .recipes import (
|
||||
IndexableDict,
|
||||
IndexableSet,
|
||||
ItemSortedDict,
|
||||
OrderedSet,
|
||||
SegmentList,
|
||||
ValueSortedDict,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
'IndexableDict',
|
||||
'IndexableSet',
|
||||
'ItemSortedDict',
|
||||
'NearestDict',
|
||||
'OrderedDict',
|
||||
'OrderedSet',
|
||||
'SegmentList',
|
||||
'SortedDict',
|
||||
'SortedList',
|
||||
'SortedListWithKey',
|
||||
'SortedSet',
|
||||
'ValueSortedDict',
|
||||
]
|
||||
|
||||
__version__ = '2.1.0'
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,123 @@
|
||||
"""NearestDict implementation.
|
||||
|
||||
One primary use case for this data structure is storing data by a
|
||||
`datetime.datetime` or `float` key.
|
||||
"""
|
||||
|
||||
from sortedcontainers import SortedDict
|
||||
|
||||
|
||||
class NearestDict(SortedDict):
|
||||
"""A dict using nearest-key lookup.
|
||||
|
||||
A :class:`SortedDict` subclass that uses nearest-key lookup instead of
|
||||
exact-key lookup. Optionally, you can specify a rounding mode to return the
|
||||
nearest key less than or equal to or greater than or equal to the provided
|
||||
key.
|
||||
|
||||
When using :attr:`NearestDict.NEAREST` the keys must support subtraction to
|
||||
allow finding the nearest key (by find the key with the smallest difference
|
||||
to the given one).
|
||||
|
||||
Additional methods:
|
||||
|
||||
* :meth:`NearestDict.nearest_key`
|
||||
|
||||
Example usage:
|
||||
|
||||
>>> d = NearestDict({1.0: 'foo'})
|
||||
>>> d[1.0]
|
||||
'foo'
|
||||
>>> d[0.0]
|
||||
'foo'
|
||||
>>> d[2.0]
|
||||
'foo'
|
||||
"""
|
||||
|
||||
NEAREST_PREV = -1
|
||||
NEAREST = 0
|
||||
NEAREST_NEXT = 1
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Initialize a NearestDict instance.
|
||||
|
||||
Optional `rounding` argument dictates how
|
||||
:meth:`NearestDict.nearest_key` rounds. It must be one of
|
||||
:attr:`NearestDict.NEAREST_NEXT`, :attr:`NearestDict.NEAREST`, or
|
||||
:attr:`NearestDict.NEAREST_PREV`. (Default:
|
||||
:attr:`NearestDict.NEAREST`)
|
||||
|
||||
:params rounding: how to round on nearest-key lookup (optional)
|
||||
:params args: positional arguments for :class:`SortedDict`.
|
||||
:params kwargs: keyword arguments for :class:`SortedDict`.
|
||||
"""
|
||||
self.rounding = kwargs.pop('rounding', self.NEAREST)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def nearest_key(self, request):
|
||||
"""Return nearest-key to `request`, respecting `self.rounding`.
|
||||
|
||||
>>> d = NearestDict({1.0: 'foo'})
|
||||
>>> d.nearest_key(0.0)
|
||||
1.0
|
||||
>>> d.nearest_key(2.0)
|
||||
1.0
|
||||
|
||||
>>> d = NearestDict({1.0: 'foo'}, rounding=NearestDict.NEAREST_PREV)
|
||||
>>> d.nearest_key(0.0)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
KeyError: 'No key below 0.0 found'
|
||||
>>> d.nearest_key(2.0)
|
||||
1.0
|
||||
|
||||
:param request: nearest-key lookup value
|
||||
:return: key nearest to `request`, respecting `rounding`
|
||||
:raises KeyError: if no appropriate key can be found
|
||||
"""
|
||||
key_list = self.keys()
|
||||
|
||||
if not key_list:
|
||||
raise KeyError('NearestDict is empty')
|
||||
|
||||
index = self.bisect_left(request)
|
||||
|
||||
if index >= len(key_list):
|
||||
if self.rounding == self.NEAREST_NEXT:
|
||||
raise KeyError(f'No key above {request!r} found')
|
||||
return key_list[index - 1]
|
||||
if key_list[index] == request:
|
||||
return key_list[index]
|
||||
if index == 0 and self.rounding == self.NEAREST_PREV:
|
||||
raise KeyError(f'No key below {request!r} found')
|
||||
if self.rounding == self.NEAREST_PREV:
|
||||
return key_list[index - 1]
|
||||
if self.rounding == self.NEAREST_NEXT:
|
||||
return key_list[index]
|
||||
if abs(key_list[index - 1] - request) < abs(key_list[index] - request):
|
||||
return key_list[index - 1]
|
||||
return key_list[index]
|
||||
|
||||
def __getitem__(self, request):
|
||||
"""Return item corresponding to :meth:`.nearest_key`.
|
||||
|
||||
:param request: nearest-key lookup value
|
||||
:return: item corresponding to key nearest `request`
|
||||
:raises KeyError: if no appropriate item can be found
|
||||
|
||||
>>> d = NearestDict({1.0: 'foo'})
|
||||
>>> d[0.0]
|
||||
'foo'
|
||||
>>> d[2.0]
|
||||
'foo'
|
||||
|
||||
>>> d = NearestDict({1.0: 'foo'}, rounding=NearestDict.NEAREST_NEXT)
|
||||
>>> d[0.0]
|
||||
'foo'
|
||||
>>> d[2.0]
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
KeyError: 'No key above 2.0 found'
|
||||
"""
|
||||
key = self.nearest_key(request)
|
||||
return super().__getitem__(key)
|
||||
@@ -0,0 +1,207 @@
|
||||
"""Ordered dictionary implementation.
|
||||
|
||||
"""
|
||||
|
||||
from itertools import count
|
||||
from operator import eq
|
||||
|
||||
from sortedcontainers import SortedDict
|
||||
from sortedcontainers.sortedlist import recursive_repr
|
||||
|
||||
from .recipes import abc
|
||||
|
||||
NONE = object()
|
||||
|
||||
|
||||
class KeysView(abc.KeysView, abc.Sequence):
|
||||
"Read-only view of mapping keys."
|
||||
# noqa pylint: disable=too-few-public-methods,protected-access,too-many-ancestors
|
||||
def __getitem__(self, index):
|
||||
"``keys_view[index]``"
|
||||
_nums = self._mapping._nums
|
||||
if isinstance(index, slice):
|
||||
nums = _nums._list[index]
|
||||
return [_nums[num] for num in nums]
|
||||
return _nums[_nums._list[index]]
|
||||
|
||||
|
||||
class ItemsView(abc.ItemsView, abc.Sequence):
|
||||
"Read-only view of mapping items."
|
||||
# noqa pylint: disable=too-few-public-methods,protected-access,too-many-ancestors
|
||||
def __getitem__(self, index):
|
||||
"``items_view[index]``"
|
||||
_mapping = self._mapping
|
||||
_nums = _mapping._nums
|
||||
if isinstance(index, slice):
|
||||
nums = _nums._list[index]
|
||||
keys = [_nums[num] for num in nums]
|
||||
return [(key, _mapping[key]) for key in keys]
|
||||
num = _nums._list[index]
|
||||
key = _nums[num]
|
||||
return key, _mapping[key]
|
||||
|
||||
|
||||
class ValuesView(abc.ValuesView, abc.Sequence):
|
||||
"Read-only view of mapping values."
|
||||
# noqa pylint: disable=too-few-public-methods,protected-access,too-many-ancestors
|
||||
def __getitem__(self, index):
|
||||
"``items_view[index]``"
|
||||
_mapping = self._mapping
|
||||
_nums = _mapping._nums
|
||||
if isinstance(index, slice):
|
||||
nums = _nums._list[index]
|
||||
keys = [_nums[num] for num in nums]
|
||||
return [_mapping[key] for key in keys]
|
||||
num = _nums._list[index]
|
||||
key = _nums[num]
|
||||
return _mapping[key]
|
||||
|
||||
|
||||
class OrderedDict(dict):
|
||||
"""Dictionary that remembers insertion order and is numerically indexable.
|
||||
|
||||
Keys are numerically indexable using dict views. For example::
|
||||
|
||||
>>> ordered_dict = OrderedDict.fromkeys('abcde')
|
||||
>>> keys = ordered_dict.keys()
|
||||
>>> keys[0]
|
||||
'a'
|
||||
>>> keys[-2:]
|
||||
['d', 'e']
|
||||
|
||||
The dict views support the sequence abstract base class.
|
||||
|
||||
"""
|
||||
|
||||
# pylint: disable=super-init-not-called
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._keys = {}
|
||||
self._nums = SortedDict()
|
||||
self._keys_view = self._nums.keys()
|
||||
self._count = count()
|
||||
self.update(*args, **kwargs)
|
||||
|
||||
def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
|
||||
"``ordered_dict[key] = value``"
|
||||
if key not in self:
|
||||
num = next(self._count)
|
||||
self._keys[key] = num
|
||||
self._nums[num] = key
|
||||
dict_setitem(self, key, value)
|
||||
|
||||
def __delitem__(self, key, dict_delitem=dict.__delitem__):
|
||||
"``del ordered_dict[key]``"
|
||||
dict_delitem(self, key)
|
||||
num = self._keys.pop(key)
|
||||
del self._nums[num]
|
||||
|
||||
def __iter__(self):
|
||||
"``iter(ordered_dict)``"
|
||||
return iter(self._nums.values())
|
||||
|
||||
def __reversed__(self):
|
||||
"``reversed(ordered_dict)``"
|
||||
nums = self._nums
|
||||
for key in reversed(nums):
|
||||
yield nums[key]
|
||||
|
||||
def clear(self, dict_clear=dict.clear):
|
||||
"Remove all items from mapping."
|
||||
dict_clear(self)
|
||||
self._keys.clear()
|
||||
self._nums.clear()
|
||||
|
||||
def popitem(self, last=True):
|
||||
"""Remove and return (key, value) item pair.
|
||||
|
||||
Pairs are returned in LIFO order if last is True or FIFO order if
|
||||
False.
|
||||
|
||||
"""
|
||||
index = -1 if last else 0
|
||||
num = self._keys_view[index]
|
||||
key = self._nums[num]
|
||||
value = self.pop(key)
|
||||
return key, value
|
||||
|
||||
update = __update = abc.MutableMapping.update
|
||||
|
||||
def keys(self):
|
||||
"Return set-like and sequence-like view of mapping keys."
|
||||
return KeysView(self)
|
||||
|
||||
def items(self):
|
||||
"Return set-like and sequence-like view of mapping items."
|
||||
return ItemsView(self)
|
||||
|
||||
def values(self):
|
||||
"Return set-like and sequence-like view of mapping values."
|
||||
return ValuesView(self)
|
||||
|
||||
def pop(self, key, default=NONE):
|
||||
"""Remove given key and return corresponding value.
|
||||
|
||||
If key is not found, default is returned if given, otherwise raise
|
||||
KeyError.
|
||||
|
||||
"""
|
||||
if key in self:
|
||||
value = self[key]
|
||||
del self[key]
|
||||
return value
|
||||
if default is NONE:
|
||||
raise KeyError(key)
|
||||
return default
|
||||
|
||||
def setdefault(self, key, default=None):
|
||||
"""Return ``mapping.get(key, default)``, also set ``mapping[key] = default`` if
|
||||
key not in mapping.
|
||||
|
||||
"""
|
||||
if key in self:
|
||||
return self[key]
|
||||
self[key] = default
|
||||
return default
|
||||
|
||||
@recursive_repr()
|
||||
def __repr__(self):
|
||||
"Text representation of mapping."
|
||||
return f'{self.__class__.__name__}({list(self.items())!r})'
|
||||
|
||||
__str__ = __repr__
|
||||
|
||||
def __reduce__(self):
|
||||
"Support for pickling serialization."
|
||||
return (self.__class__, (list(self.items()),))
|
||||
|
||||
def copy(self):
|
||||
"Return shallow copy of mapping."
|
||||
return self.__class__(self)
|
||||
|
||||
@classmethod
|
||||
def fromkeys(cls, iterable, value=None):
|
||||
"""Return new mapping with keys from iterable.
|
||||
|
||||
If not specified, value defaults to None.
|
||||
|
||||
"""
|
||||
return cls((key, value) for key in iterable)
|
||||
|
||||
def __eq__(self, other):
|
||||
"Test self and other mapping for equality."
|
||||
if isinstance(other, OrderedDict):
|
||||
return dict.__eq__(self, other) and all(map(eq, self, other))
|
||||
return dict.__eq__(self, other)
|
||||
|
||||
__ne__ = abc.MutableMapping.__ne__
|
||||
|
||||
def _check(self):
|
||||
"Check consistency of internal member variables."
|
||||
# pylint: disable=protected-access
|
||||
keys = self._keys
|
||||
nums = self._nums
|
||||
|
||||
for key, value in keys.items():
|
||||
assert nums[value] == key
|
||||
|
||||
nums._check()
|
||||
@@ -0,0 +1,345 @@
|
||||
"""Sorted collections recipes implementations.
|
||||
|
||||
"""
|
||||
|
||||
from collections import abc
|
||||
from copy import deepcopy
|
||||
from itertools import count
|
||||
|
||||
from sortedcontainers import SortedDict, SortedKeyList, SortedSet
|
||||
from sortedcontainers.sortedlist import recursive_repr
|
||||
|
||||
|
||||
class IndexableDict(SortedDict):
|
||||
"""Dictionary that supports numerical indexing.
|
||||
|
||||
Keys are numerically indexable using dict views. For example::
|
||||
|
||||
>>> indexable_dict = IndexableDict.fromkeys('abcde')
|
||||
>>> keys = indexable_dict.keys()
|
||||
>>> sorted(keys[:]) == ['a', 'b', 'c', 'd', 'e']
|
||||
True
|
||||
|
||||
The dict views support the sequence abstract base class.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(hash, *args, **kwargs)
|
||||
|
||||
|
||||
class IndexableSet(SortedSet):
|
||||
"""Set that supports numerical indexing.
|
||||
|
||||
Values are numerically indexable. For example::
|
||||
|
||||
>>> indexable_set = IndexableSet('abcde')
|
||||
>>> sorted(indexable_set[:]) == ['a', 'b', 'c', 'd', 'e']
|
||||
True
|
||||
|
||||
`IndexableSet` implements the sequence abstract base class.
|
||||
|
||||
"""
|
||||
|
||||
# pylint: disable=too-many-ancestors
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, key=hash, **kwargs)
|
||||
|
||||
def __reduce__(self):
|
||||
return self.__class__, (set(self),)
|
||||
|
||||
|
||||
class ItemSortedDict(SortedDict):
|
||||
"""Sorted dictionary with key-function support for item pairs.
|
||||
|
||||
Requires key function callable specified as the first argument. The
|
||||
callable must accept two arguments, key and value, and return a value used
|
||||
to determine the sort order. For example::
|
||||
|
||||
def multiply(key, value):
|
||||
return key * value
|
||||
mapping = ItemSortedDict(multiply, [(3, 2), (4, 1), (2, 5)])
|
||||
list(mapping) == [4, 3, 2]
|
||||
|
||||
Above, the key/value item pairs are ordered by ``key * value`` according to
|
||||
the callable given as the first argument.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
assert args and callable(args[0])
|
||||
args = list(args)
|
||||
func = self._func = args[0]
|
||||
|
||||
def key_func(key):
|
||||
"Apply key function to (key, value) item pair."
|
||||
return func(key, self[key])
|
||||
|
||||
args[0] = key_func
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def __delitem__(self, key):
|
||||
"``del mapping[key]``"
|
||||
if key not in self:
|
||||
raise KeyError(key)
|
||||
self._list_remove(key)
|
||||
dict.__delitem__(self, key)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
"``mapping[key] = value``"
|
||||
if key in self:
|
||||
self._list_remove(key)
|
||||
dict.__delitem__(self, key)
|
||||
dict.__setitem__(self, key, value)
|
||||
self._list_add(key)
|
||||
|
||||
_setitem = __setitem__
|
||||
|
||||
def copy(self):
|
||||
"Return shallow copy of the mapping."
|
||||
return self.__class__(self._func, iter(self.items()))
|
||||
|
||||
__copy__ = copy
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
items = (deepcopy(item, memo) for item in self.items())
|
||||
return self.__class__(self._func, items)
|
||||
|
||||
|
||||
class ValueSortedDict(SortedDict):
|
||||
"""Sorted dictionary that maintains (key, value) item pairs sorted by value.
|
||||
|
||||
- ``ValueSortedDict()`` -> new empty dictionary.
|
||||
|
||||
- ``ValueSortedDict(mapping)`` -> new dictionary initialized from a mapping
|
||||
object's (key, value) pairs.
|
||||
|
||||
- ``ValueSortedDict(iterable)`` -> new dictionary initialized as if via::
|
||||
|
||||
d = ValueSortedDict()
|
||||
for k, v in iterable:
|
||||
d[k] = v
|
||||
|
||||
- ``ValueSortedDict(**kwargs)`` -> new dictionary initialized with the
|
||||
name=value pairs in the keyword argument list. For example::
|
||||
|
||||
ValueSortedDict(one=1, two=2)
|
||||
|
||||
An optional key function callable may be specified as the first
|
||||
argument. When so, the callable will be applied to the value of each item
|
||||
pair to determine the comparable for sort order as with Python's builtin
|
||||
``sorted`` function.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
args = list(args)
|
||||
if args and callable(args[0]):
|
||||
func = self._func = args[0]
|
||||
|
||||
def key_func(key):
|
||||
"Apply key function to ``mapping[value]``."
|
||||
return func(self[key])
|
||||
|
||||
args[0] = key_func
|
||||
else:
|
||||
self._func = None
|
||||
|
||||
def key_func(key):
|
||||
"Return mapping value for key."
|
||||
return self[key]
|
||||
|
||||
if args and args[0] is None:
|
||||
args[0] = key_func
|
||||
else:
|
||||
args.insert(0, key_func)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def __delitem__(self, key):
|
||||
"``del mapping[key]``"
|
||||
if key not in self:
|
||||
raise KeyError(key)
|
||||
self._list_remove(key)
|
||||
dict.__delitem__(self, key)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
"``mapping[key] = value``"
|
||||
if key in self:
|
||||
self._list_remove(key)
|
||||
dict.__delitem__(self, key)
|
||||
dict.__setitem__(self, key, value)
|
||||
self._list_add(key)
|
||||
|
||||
_setitem = __setitem__
|
||||
|
||||
def copy(self):
|
||||
"Return shallow copy of the mapping."
|
||||
return self.__class__(self._func, iter(self.items()))
|
||||
|
||||
__copy__ = copy
|
||||
|
||||
def __reduce__(self):
|
||||
items = [(key, self[key]) for key in self._list]
|
||||
args = (self._func, items)
|
||||
return (self.__class__, args)
|
||||
|
||||
@recursive_repr()
|
||||
def __repr__(self):
|
||||
items = ', '.join(f'{key!r}: {self[key]!r}' for key in self._list)
|
||||
return f'{self.__class__.__name__}({self._func!r}, {{{items}}})'
|
||||
|
||||
|
||||
class OrderedSet(abc.MutableSet, abc.Sequence):
|
||||
"""Like OrderedDict, OrderedSet maintains the insertion order of elements.
|
||||
|
||||
For example::
|
||||
|
||||
>>> ordered_set = OrderedSet('abcde')
|
||||
>>> list(ordered_set) == list('abcde')
|
||||
True
|
||||
>>> ordered_set = OrderedSet('edcba')
|
||||
>>> list(ordered_set) == list('edcba')
|
||||
True
|
||||
|
||||
OrderedSet also implements the collections.Sequence interface.
|
||||
|
||||
"""
|
||||
|
||||
# pylint: disable=too-many-ancestors
|
||||
def __init__(self, iterable=()):
|
||||
# pylint: disable=super-init-not-called
|
||||
self._keys = {}
|
||||
self._nums = SortedDict()
|
||||
self._keys_view = self._nums.keys()
|
||||
self._count = count()
|
||||
self |= iterable
|
||||
|
||||
def __contains__(self, key):
|
||||
"``key in ordered_set``"
|
||||
return key in self._keys
|
||||
|
||||
count = __contains__
|
||||
|
||||
def __iter__(self):
|
||||
"``iter(ordered_set)``"
|
||||
return iter(self._nums.values())
|
||||
|
||||
def __reversed__(self):
|
||||
"``reversed(ordered_set)``"
|
||||
_nums = self._nums
|
||||
for key in reversed(_nums):
|
||||
yield _nums[key]
|
||||
|
||||
def __getitem__(self, index):
|
||||
"``ordered_set[index]`` -> element; lookup element at index."
|
||||
num = self._keys_view[index]
|
||||
return self._nums[num]
|
||||
|
||||
def __len__(self):
|
||||
"``len(ordered_set)``"
|
||||
return len(self._keys)
|
||||
|
||||
def index(self, value):
|
||||
"Return index of value."
|
||||
# pylint: disable=arguments-differ
|
||||
try:
|
||||
return self._keys[value]
|
||||
except KeyError:
|
||||
raise ValueError(f'{value!r} is not in {type(self).__name__}')
|
||||
|
||||
def add(self, value):
|
||||
"Add element, value, to set."
|
||||
if value not in self._keys:
|
||||
num = next(self._count)
|
||||
self._keys[value] = num
|
||||
self._nums[num] = value
|
||||
|
||||
def discard(self, value):
|
||||
"Remove element, value, from set if it is a member."
|
||||
num = self._keys.pop(value, None)
|
||||
if num is not None:
|
||||
del self._nums[num]
|
||||
|
||||
def __repr__(self):
|
||||
"Text representation of set."
|
||||
return f'{type(self).__name__}({list(self)!r})'
|
||||
|
||||
__str__ = __repr__
|
||||
|
||||
|
||||
class SegmentList(SortedKeyList):
|
||||
"""List that supports fast random insertion and deletion of elements.
|
||||
|
||||
SegmentList is a special case of a SortedList initialized with a key
|
||||
function that always returns 0. As such, several SortedList methods are not
|
||||
implemented for SegmentList.
|
||||
|
||||
"""
|
||||
|
||||
# pylint: disable=too-many-ancestors
|
||||
def __init__(self, iterable=()):
|
||||
super().__init__(iterable, self.zero)
|
||||
|
||||
@staticmethod
|
||||
def zero(_):
|
||||
"Return 0."
|
||||
return 0
|
||||
|
||||
def __setitem__(self, index, value):
|
||||
if isinstance(index, slice):
|
||||
raise NotImplementedError
|
||||
pos, idx = self._pos(index)
|
||||
self._lists[pos][idx] = value
|
||||
|
||||
def append(self, value):
|
||||
if self._len:
|
||||
pos = len(self._lists) - 1
|
||||
self._lists[pos].append(value)
|
||||
self._keys[pos].append(0)
|
||||
self._expand(pos)
|
||||
else:
|
||||
self._lists.append([value])
|
||||
self._keys.append([0])
|
||||
self._maxes.append(0)
|
||||
self._len += 1
|
||||
|
||||
def extend(self, values):
|
||||
for value in values:
|
||||
self.append(value)
|
||||
|
||||
def insert(self, index, value):
|
||||
if index == self._len:
|
||||
self.append(value)
|
||||
return
|
||||
pos, idx = self._pos(index)
|
||||
self._lists[pos].insert(idx, value)
|
||||
self._keys[pos].insert(idx, 0)
|
||||
self._expand(pos)
|
||||
self._len += 1
|
||||
|
||||
def reverse(self):
|
||||
values = list(self)
|
||||
values.reverse()
|
||||
self.clear()
|
||||
self.extend(values)
|
||||
|
||||
def sort(self, key=None, reverse=False):
|
||||
"Stable sort in place."
|
||||
values = sorted(self, key=key, reverse=reverse)
|
||||
self.clear()
|
||||
self.extend(values)
|
||||
|
||||
def _not_implemented(self, *args, **kwargs):
|
||||
"Not implemented."
|
||||
raise NotImplementedError
|
||||
|
||||
add = _not_implemented
|
||||
bisect = _not_implemented
|
||||
bisect_left = _not_implemented
|
||||
bisect_right = _not_implemented
|
||||
bisect_key = _not_implemented
|
||||
bisect_key_left = _not_implemented
|
||||
bisect_key_right = _not_implemented
|
||||
irange = _not_implemented
|
||||
irange_key = _not_implemented
|
||||
update = _not_implemented
|
||||
Reference in New Issue
Block a user