Pure-Python sorted containers: SortedList, SortedDict, SortedSet. Drop-in sortedcontainers replacement.
Project description
sortsmith
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bc33b8eaa0579f7abab6340797ad7eec99d357116d268a712f6b5dd5c66eec20
|
|
| MD5 |
1cd8e4524c4d2dc46c16b59dd718612b
|
|
| BLAKE2b-256 |
dde24e2e8d647515bf406f8aab2e2294d18671156f1de0b78ba93de916dbda4b
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bcbd308b69420c5a995a98e727f4653f153bb36dafe8fa95325b3d7e5bf14aba
|
|
| MD5 |
624aa4daa7f7582db9c9cbc74d52efa4
|
|
| BLAKE2b-256 |
b8bab137f1440d880ff52ba4e136b11b0f74c7276993fe21e8c938f7cc795607
|