Skip to content

add SortedArray #183

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions sortedcontainers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -54,6 +57,7 @@
SortedItemsView,
SortedValuesView,
)
from .sortedarray import SortedArray

__all__ = [
'SortedList',
Expand All @@ -64,6 +68,7 @@
'SortedItemsView',
'SortedValuesView',
'SortedSet',
'SortedArray'
]

__title__ = 'sortedcontainers'
Expand Down
143 changes: 143 additions & 0 deletions sortedcontainers/sortedarray.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
"""Sorted Array
===============


:doc:`Sorted Containers<index>` is an Apache2 licensed Python sorted
collections library, written in pure-Python, and fast as C-extensions. The
:doc:`introduction<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 sys import hexversion

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 array instance.

Optional `iterable` argument provides an initial iterable of values to
initialize the sorted array.

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
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
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):
_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))
41 changes: 31 additions & 10 deletions sortedcontainers/sortedlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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__
Expand All @@ -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
Expand Down Expand Up @@ -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,))


Expand Down