From 5fb534df561f415c1caf6413d05145a355081708 Mon Sep 17 00:00:00 2001 From: Sergiy Subota Date: Fri, 24 Dec 2021 00:07:03 -0500 Subject: [PATCH 1/3] add SoretedArray --- sortedcontainers/__init__.py | 5 ++ sortedcontainers/sortedarray.py | 135 ++++++++++++++++++++++++++++++++ sortedcontainers/sortedlist.py | 41 +++++++--- 3 files changed, 171 insertions(+), 10 deletions(-) create mode 100644 sortedcontainers/sortedarray.py diff --git a/sortedcontainers/__init__.py b/sortedcontainers/__init__.py index a141dd1d..8f973e10 100644 --- a/sortedcontainers/__init__.py +++ b/sortedcontainers/__init__.py @@ -34,6 +34,9 @@ SortedSet(['a', 'b', 'c', 'd', 'r']) >>> ss.bisect_left('c') 2 + >>> sa = SortedArray('i', [5,7,3,6,2,1,4]) + >>> sa + SortedArray('i', [1, 2, 3, 4, 5, 6, 7]) Sorted Containers takes all of the work out of Python sorted types - making your deployment and use of Python easy. There's no need to install a C compiler @@ -54,6 +57,7 @@ SortedItemsView, SortedValuesView, ) +from .sortedarray import SortedArray __all__ = [ 'SortedList', @@ -64,6 +68,7 @@ 'SortedItemsView', 'SortedValuesView', 'SortedSet', + 'SortedArray' ] __title__ = 'sortedcontainers' diff --git a/sortedcontainers/sortedarray.py b/sortedcontainers/sortedarray.py new file mode 100644 index 00000000..a91bb488 --- /dev/null +++ b/sortedcontainers/sortedarray.py @@ -0,0 +1,135 @@ +"""Sorted Array +=============== + + +:doc:`Sorted Containers` is an Apache2 licensed Python sorted +collections library, written in pure-Python, and fast as C-extensions. The +:doc:`introduction` is the best way to get started. + +Sorted list implementations: + +.. currentmodule:: sortedcontainers + +* :class:`SortedArray` + +""" +# pylint: disable=too-many-lines +from __future__ import print_function +from .sortedlist import SortedList, recursive_repr +from array import array + +class SortedArray(SortedList): + """Sorted array is a sorted mutable sequence. + + Sorted array values are maintained in sorted order. + + Underlying data structure is the standard library array.array + Enables densly packed lists floats and doubles. + Enables densly packed lists of integers in CPython. + + Methods for adding values: + + * :func:`SortedArray.add` + * :func:`SortedArray.update` + * :func:`SortedArray.__add__` + * :func:`SortedArray.__iadd__` + * :func:`SortedArray.__mul__` + * :func:`SortedArray.__imul__` + + Methods for removing values: + + * :func:`SortedArray.clear` + * :func:`SortedArray.discard` + * :func:`SortedArray.remove` + * :func:`SortedArray.pop` + * :func:`SortedArray.__delitem__` + + Methods for looking up values: + + * :func:`SortedArray.bisect_left` + * :func:`SortedArray.bisect_right` + * :func:`SortedArray.count` + * :func:`SortedArray.index` + * :func:`SortedArray.__contains__` + * :func:`SortedArray.__getitem__` + + Methods for iterating values: + + * :func:`SortedArray.irange` + * :func:`SortedArray.islice` + * :func:`SortedArray.__iter__` + * :func:`SortedArray.__reversed__` + + Methods for miscellany: + + * :func:`SortedArray.copy` + * :func:`SortedArray.__len__` + * :func:`SortedArray.__repr__` + * :func:`SortedArray._check` + * :func:`SortedArray._reset` + + Sorted lists use lexicographical ordering semantics when compared to other + sequences. + + Some methods of mutable sequences are not supported and will raise + not-implemented error. + + """ + DEFAULT_LOAD_FACTOR = 1000 + + + def __init__(self, typecode, initializer=None): + """Initialize sorted list instance. + + Optional `iterable` argument provides an initial iterable of values to + initialize the sorted list. + + Runtime complexity: `O(n*log(n))` + + >>> sl = SortedArray('i') + >>> sl + SortedArray('i', []) + >>> sl = SortedArray('i', [3, 1, 2, 5, 4]) + >>> sl + SortedArray('i', [1, 2, 3, 4, 5]) + + :param typecode: type code for the array, as in the array.array standard library class (required) + :param iterable: initial values (optional) + + """ + self._typecode = typecode + super().__init__(iterable=initializer, key=None) + + + def __new__(cls, typecode, initializer=None): + # pylint: disable=unused-argument + return super().__new__(cls, iterable=initializer, key=None) + + + def _new_list(self): + _typecode = self._typecode + return array(_typecode) + + + def _sort_in_place(self, _list): + # array.array does not support sort in place + sorted_list = sorted(_list) + del _list[:] + _list.extend(sorted_list) + + + @recursive_repr() + def __repr__(self): + """Return string representation of sorted array. + + ``sa.__repr__()`` <==> ``repr(sa)`` + + :return: string representation + + >>> sa = SortedArray('i',[5,4,3]) + >>> sa + SortedArray('i', [3, 4, 5]) + """ + class_name = type(self).__name__ + _typecode = self._typecode + return "{0}('{1}', {2!r})".format(class_name, _typecode, list(self)) diff --git a/sortedcontainers/sortedlist.py b/sortedcontainers/sortedlist.py index e3b58eb9..ee202a30 100644 --- a/sortedcontainers/sortedlist.py +++ b/sortedcontainers/sortedlist.py @@ -160,10 +160,11 @@ def __init__(self, iterable=None, key=None): """ assert key is None + _new_list = self._new_list self._len = 0 self._load = self.DEFAULT_LOAD_FACTOR self._lists = [] - self._maxes = [] + self._maxes = _new_list() self._index = [] self._offset = 0 @@ -201,6 +202,14 @@ def __new__(cls, iterable=None, key=None): raise TypeError('inherit SortedKeyList for key argument') + def _new_list(self): + return [] + + + def _sort_in_place(self, _list): + _list.sort() + + @property def key(self): # pylint: disable=useless-return """Function used to extract comparison key from values. @@ -229,7 +238,8 @@ def _reset(self, load): :param int load: load-factor for sorted list sublists """ - values = reduce(iadd, self._lists, []) + _new_list = self._new_list + values = reduce(iadd, self._lists, _new_list()) self._clear() self._load = load self._update(values) @@ -280,7 +290,10 @@ def add(self, value): self._expand(pos) else: - _lists.append([value]) + _new_list = self._new_list + new_list = _new_list() + new_list.append(value) + _lists.append(new_list) _maxes.append(value) self._len += 1 @@ -335,13 +348,16 @@ def update(self, iterable): """ _lists = self._lists _maxes = self._maxes - values = sorted(iterable) + _new_list = self._new_list + _sort_in_place = self._sort_in_place + values = _new_list() + values.extend(iterable) if _maxes: if len(values) * 4 >= self._len: _lists.append(values) - values = reduce(iadd, _lists, []) - values.sort() + values = reduce(iadd, _lists, _new_list()) + _sort_in_place(values) self._clear() else: _add = self.add @@ -350,6 +366,7 @@ def update(self, iterable): return _load = self._load + _sort_in_place(values) _lists.extend(values[pos:(pos + _load)] for pos in range(0, len(values), _load)) _maxes.extend(sublist[-1] for sublist in _lists) @@ -1471,7 +1488,8 @@ def __add__(self, other): :return: new sorted list """ - values = reduce(iadd, self._lists, []) + _new_list = self._new_list + values = reduce(iadd, self._lists, _new_list()) values.extend(other) return self.__class__(values) @@ -1515,7 +1533,8 @@ def __mul__(self, num): :return: new sorted list """ - values = reduce(iadd, self._lists, []) * num + _new_list = self._new_list + values = reduce(iadd, self._lists, _new_list()) * num return self.__class__(values) __rmul__ = __mul__ @@ -1537,7 +1556,8 @@ def __imul__(self, num): :return: existing sorted list """ - values = reduce(iadd, self._lists, []) * num + _new_list = self._new_list + values = reduce(iadd, self._lists, _new_list()) * num self._clear() self._update(values) return self @@ -1593,7 +1613,8 @@ def comparer(self, other): def __reduce__(self): - values = reduce(iadd, self._lists, []) + _new_list = self._new_list + values = reduce(iadd, self._lists, _new_list()) return (type(self), (values,)) From af9c78a969b1a4f473ab3e10eff7e1f28fee67db Mon Sep 17 00:00:00 2001 From: Sergiy Subota Date: Fri, 24 Dec 2021 01:08:45 -0500 Subject: [PATCH 2/3] fix support python2.7 in SortedArray --- sortedcontainers/sortedarray.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sortedcontainers/sortedarray.py b/sortedcontainers/sortedarray.py index a91bb488..6a096bb9 100644 --- a/sortedcontainers/sortedarray.py +++ b/sortedcontainers/sortedarray.py @@ -15,6 +15,8 @@ """ # pylint: disable=too-many-lines from __future__ import print_function +from sys import hexversion + from .sortedlist import SortedList, recursive_repr from array import array @@ -98,12 +100,18 @@ def __init__(self, typecode, initializer=None): """ self._typecode = typecode - super().__init__(iterable=initializer, key=None) + if hexversion >= 0x03000000: + super().__init__(iterable=initializer, key=None) + else: + super(SortedArray, self).__init__(iterable=initializer, key=None) def __new__(cls, typecode, initializer=None): # pylint: disable=unused-argument - return super().__new__(cls, iterable=initializer, key=None) + if hexversion >= 0x03000000: + return super().__new__(cls, iterable=initializer, key=None) + else: + return super(SortedArray, cls).__new__(cls, iterable=initializer, key=None) def _new_list(self): From cbdf4e1bdc115d8b962141b46191c6e3e6b2aac7 Mon Sep 17 00:00:00 2001 From: bsamedi Date: Tue, 18 Oct 2022 19:03:50 -0400 Subject: [PATCH 3/3] Apply suggestions from code review fix docstrings Co-authored-by: ilemhadri <19997801+ilemhadri@users.noreply.github.com> --- sortedcontainers/sortedarray.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sortedcontainers/sortedarray.py b/sortedcontainers/sortedarray.py index 6a096bb9..fa84bf0c 100644 --- a/sortedcontainers/sortedarray.py +++ b/sortedcontainers/sortedarray.py @@ -81,10 +81,10 @@ class SortedArray(SortedList): def __init__(self, typecode, initializer=None): - """Initialize sorted list instance. + """Initialize sorted array instance. Optional `iterable` argument provides an initial iterable of values to - initialize the sorted list. + initialize the sorted array. Runtime complexity: `O(n*log(n))`