Skip to main content

Pure-Python sorted containers: SortedList, SortedDict, SortedSet. Drop-in sortedcontainers replacement.

Project description

sortsmith

CI PyPI Python

Pure-Python sorted containers — SortedList, SortedDict, SortedSet, SortedKeyList.

Drop-in replacement for sortedcontainers with full type annotations, Python 3.10+ support, and modern packaging.

Installation

pip install sortsmith

Quick Start

from sortsmith import SortedList, SortedDict, SortedSet

sl = SortedList([3, 1, 2])    # SortedList([1, 2, 3])
sd = SortedDict(b=2, a=1)     # SortedDict({'a': 1, 'b': 2})
ss = SortedSet([3, 1, 2])     # SortedSet([1, 2, 3])

API Reference

SortedList

A list that maintains elements in sorted order using a segmented list-of-lists structure — O(log n) insertion/deletion, O(1) amortized indexed access.

from sortsmith import SortedList

sl = SortedList([5, 1, 3])
# SortedList([1, 3, 5])

Mutation

Method Description
add(value) Add a value
discard(value) Remove if present, no-op otherwise
remove(value) Remove; raise ValueError if absent
pop(index=-1) Remove and return item at index
update(iterable) Add all values from iterable
clear() Remove all elements

Lookup

Method / Operator Description
value in sl O(log n) membership test
sl[i] Index access (int or slice)
del sl[i] Delete by index (int or slice)
len(sl) Number of elements
bisect_left(value) Leftmost insertion point
bisect_right(value) Rightmost insertion point
index(value) First index of value (raises ValueError if absent)
count(value) Count occurrences

Range iteration

# Values between 2 and 8 inclusive
list(sl.irange(2, 8))

# Values from index 1 to 4 (exclusive)
list(sl.islice(1, 4))

# Reverse iteration
list(sl.irange(2, 8, reverse=True))

# Exclusive bounds
list(sl.irange(2, 8, inclusive=(False, True)))

Operators

sl1 + sl2       # New SortedList with all elements
sl += [4, 6]    # In-place update
sl * 2          # New SortedList with elements repeated twice

SortedKeyList

Like SortedList but ordered by a key function. Elements are stored as-is; only ordering uses the key.

from sortsmith import SortedKeyList

skl = SortedKeyList(["banana", "apple", "cherry"], key=len)
# Ordered by string length: ['apple', 'banana', 'cherry']

skl = SortedKeyList(["banana", "apple", "cherry"], key=str.lower)

Additional methods (beyond SortedList):

Method Description
bisect_key_left(key) Leftmost insertion point by key value
bisect_key_right(key) Rightmost insertion point by key value
irange_key(min_key, max_key) Iterate over values whose keys are in range
skl.key The key function

SortedDict

A dict subclass whose keys are kept in sorted order. All dict operations are supported; keys/values/items views iterate in sorted key order.

from sortsmith import SortedDict

sd = SortedDict({"c": 3, "a": 1, "b": 2})
# SortedDict({'a': 1, 'b': 2, 'c': 3})

list(sd.keys())    # ['a', 'b', 'c']
list(sd.values())  # [1, 2, 3]
list(sd.items())   # [('a', 1), ('b', 2), ('c', 3)]

# Direct iteration and reversed() also follow sorted key order
list(sd)           # ['a', 'b', 'c']
list(reversed(sd)) # ['c', 'b', 'a']

Positional access

sd.peekitem(0)    # ('a', 1) — first item by key, no removal
sd.peekitem(-1)   # ('c', 3) — last item by key, no removal
sd.popitem(0)     # ('a', 1) — remove and return first item

sd.iloc[0]        # 'a' — key at sorted position 0
sd.iloc[-1]       # 'c' — key at last sorted position
sd.iloc[1:3]      # ['b', 'c'] — slice of sorted keys

Range iteration over keys

list(sd.irange("a", "b"))             # ['a', 'b']
list(sd.irange("a", "b", inclusive=(True, False)))  # ['a']
list(sd.irange(reverse=True))         # ['c', 'b', 'a']

Bisect

sd.bisect_left("b")   # 1
sd.bisect_right("b")  # 2

Key function

# Sort keys case-insensitively
sd = SortedDict(str.lower, {"Banana": 1, "apple": 2, "Cherry": 3})
list(sd.keys())  # ['apple', 'Banana', 'Cherry']

SortedSet

A set that maintains elements in sorted order. Backed by a set (O(1) membership) and a SortedList (for ordering and range queries).

from sortsmith import SortedSet

ss = SortedSet([3, 1, 4, 1, 5])
# SortedSet([1, 3, 4, 5]) — duplicates removed, sorted

3 in ss    # True (O(1))
ss[0]      # 1 — indexed access

Mutation

Method Description
add(value) Add value (no-op if already present)
discard(value) Remove if present
remove(value) Remove; raise KeyError if absent
pop(index=-1) Remove and return item at sorted index
update(iterable) Add all values from iterable
clear() Remove all elements

Set operations (return new SortedSet)

ss1 | ss2    # Union
ss1 & ss2    # Intersection
ss1 - ss2    # Difference
ss1 ^ ss2    # Symmetric difference

ss1 <= ss2   # Subset
ss1 >= ss2   # Superset

Range iteration and positional access

list(ss.irange(2, 5))          # Values between 2 and 5
list(ss.islice(1, 3))          # Values at sorted positions 1–2
ss.bisect_left(3)              # Insertion point

Key function

ss = SortedSet(["banana", "apple", "cherry"], key=len)
list(ss)    # ['apple', 'banana', 'cherry']

Performance Notes

All four classes use a segmented list (list-of-lists) data structure with a configurable load factor (default: 1 000 elements per sublist). This gives amortised O(log n) for insertions and deletions, and O(1) amortised for indexed access.

Operation Complexity
add(value) O(log n)
discard(value) / remove(value) O(log n)
sl[i] (index access) O(log n)
value in sl O(log n)
bisect_left / bisect_right O(log n)
update(iterable) (bulk, empty list) O(k log k)
update(iterable) (incremental) O(k log n)
irange / islice O(log n + output)
len(sl) O(1)

Memory: The segmented structure stores at most ~2× the elements in sublist arrays. No external allocations — pure CPython lists throughout.

Bulk construction: Initialising with a large iterable is significantly faster than repeated add() calls. When the list is empty, update() sorts the input once (O(k log k)) and builds sublists directly.

Migration from sortedcontainers

# Before
from sortedcontainers import SortedList, SortedDict, SortedSet

# After
from sortsmith import SortedList, SortedDict, SortedSet

The API is identical. A global search-and-replace is all that's needed.

Improvements over sortedcontainers:

Feature sortedcontainers sortsmith
Last release May 2021 Active
Python support 3.7–3.12 3.10+
Type annotations Minimal Full generics (SortedList[T], SortedDict[K, V], SortedSet[T])
mypy strict No Yes
Packaging setup.py pyproject.toml + src layout

License

Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sortsmith-0.1.0.tar.gz (44.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sortsmith-0.1.0-py3-none-any.whl (15.7 kB view details)

Uploaded Python 3

File details

Details for the file sortsmith-0.1.0.tar.gz.

File metadata

  • Download URL: sortsmith-0.1.0.tar.gz
  • Upload date:
  • Size: 44.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for sortsmith-0.1.0.tar.gz
Algorithm Hash digest
SHA256 bc33b8eaa0579f7abab6340797ad7eec99d357116d268a712f6b5dd5c66eec20
MD5 1cd8e4524c4d2dc46c16b59dd718612b
BLAKE2b-256 dde24e2e8d647515bf406f8aab2e2294d18671156f1de0b78ba93de916dbda4b

See more details on using hashes here.

File details

Details for the file sortsmith-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: sortsmith-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 15.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for sortsmith-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bcbd308b69420c5a995a98e727f4653f153bb36dafe8fa95325b3d7e5bf14aba
MD5 624aa4daa7f7582db9c9cbc74d52efa4
BLAKE2b-256 b8bab137f1440d880ff52ba4e136b11b0f74c7276993fe21e8c938f7cc795607

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page