ordered-set review
ordered-set 4.1.0 supplies one Python collection, `OrderedSet`, that combines unique membership with insertion order and integer positions. A list stores values while a dictionary maps each value to its index, making membership, item-to-index lookup, and index-to-item lookup constant time. It also implements mutable-set operators, sequence slicing, NumPy-style lists of indices, and aliases used by `pandas.Index`. Version 4.1 moved the code into a package, added wheels and a `py.typed` marker, adopted Flit packaging, and raised the Python floor to 3.7.
ordered-set earns its dependency for token-to-ID tables and other append-heavy collections that need lookup in both directions. For order-preserving deduplication alone, a built-in dictionary is simpler and removes the release-cadence concern.
We installed it
| Install | ✓ · 0.2s | 1 package on disk · 1 MB |
| Import | ✓ | import ordered_set in 0.08s · pure Python · py.typed · requires Python >=3.7 |
| Known vulns | 0 | (pip-audit) |
Answers from our run
Does ordered-set install cleanly?
Yes. In a fresh container with an empty cache, pip install ordered-set finished in 0.2s, leaving 1 package and 1 MB on disk. pip-audit reported no known vulnerabilities.
What does ordered-set need to run?
Python >=3.7, and nothing compiled: it is pure Python. In our run import ordered_set succeeded in 0.08s, and the package ships py.typed for type checkers.
ordered-set or orderly-set: which should you use?
orderly-set: Use it when you want a currently released ordered-set package with a newer Python support range. ordered-set earns its dependency for token-to-ID tables and other append-heavy collections that need lookup in both directions.
When should you not use ordered-set?
You only need first-seen deduplication. list(dict.fromkeys(items)) uses the standard library and avoids another package.
Use it if
- A vocabulary builder needs `add(token)` to return a stable dense ID while duplicates reuse their existing ID.
- One value must support insertion-ordered iteration, membership checks, set algebra, slicing, and reverse lookup by position.
- NumPy arrays or lists of positions should select several unique values without pulling in pandas.
- Items are added far more often than removed, so constant-time index lookup matters more than cheap deletion.
- You only need first-seen deduplication. `list(dict.fromkeys(items))` uses the standard library and avoids another package.
- Items are deleted frequently. The README states that deletion is O(n) because later positions must be rebuilt, and a loop of removals can become quadratic.
- Released support for current Python versions matters to your policy. PyPI 4.1.0 dates to January 2022, declares Python 3.7 or newer, and its classifiers stop at Python 3.10.
- IDs must remain permanent after deletion. Removing an item shifts every later index, so previously stored integer IDs can point at the wrong value.
- Equality rules must be uniform across operand types. Ordered comparisons against sequences preserve order, while comparisons against ordinary sets ignore it.
Setup reality
We installed ordered-set 4.1.0 in a fresh unprivileged Python 3.12 Bookworm container with no cache. Installation finished in 0.2 seconds and left one package using 1 MB. Our package inspection counted 3 direct dependencies. The distribution is pure Python, requires Python 3.7 or newer, ships py.typed, and uses the MIT License. pip-audit found zero known vulnerabilities.
The distribution name contains a hyphen, but code imports OrderedSet from ordered_set. import ordered_set succeeded in 0.08 seconds in our sandbox. No compiler, credentials, service, or configuration file is involved. PyPI has a universal wheel, so the practical compatibility question is behavior on newer interpreters rather than native binary availability.
Internally, positions belong to a list and membership belongs to a dictionary. Adding an existing value returns its current position; adding a new one appends it. Deletion must remove from the list and adjust later positions, which costs O(n). Do not persist those positions as external IDs if the set can shrink. Values must also be hashable, and the mutable OrderedSet itself cannot be used as a dictionary key or nested inside another set.
Slicing returns another OrderedSet, while passing an iterable of indices returns a plain list and may repeat positions. The same index method accepts either one item or several items, so error and return types vary with the argument. Version 4.1 is still the latest PyPI release even though the repository received type-related commits in 2024. Pin 4.1.0, test it on your supported Python versions, and do not assume unreleased repository changes are installed.
Patterns
Keep the first occurrence of each item dedupe-preserving-order
from ordered_set import OrderedSet
rows = ['b', 'a', 'b', 'c', 'a']
unique = OrderedSet(rows)
assert list(unique) == ['b', 'a', 'c']If the result only needs to be a list, `list(dict.fromkeys(rows))` does the same job without this dependency.
Move between values and positions lookup-both-directions
from ordered_set import OrderedSet
letters = OrderedSet('abracadabra')
assert letters.index('r') == 2
assert letters[2] == 'r'
assert 'r' in lettersBoth lookups are constant time while the set is unchanged. Deletion shifts later positions.
Assign dense IDs while inserting intern-values
from ordered_set import OrderedSet
vocab = OrderedSet()
ids = [vocab.add(word) for word in ['the', 'cat', 'the', 'sat']]
assert ids == [0, 1, 0, 2]`add` returns the existing index for a duplicate and the appended index for a new value.
Append unseen values from an iterable bulk-update
from ordered_set import OrderedSet
items = OrderedSet([1, 2, 3])
last_index = items.update([3, 5, 4])
assert items == [1, 2, 3, 5, 4]
assert last_index == 4`update` returns the position of the final value it processed, not the number of additions.
Select several positions fancy-indexing
import numpy as np
from ordered_set import OrderedSet
letters = OrderedSet('abracadabra')
assert letters[[0, 2, 3]] == ['a', 'r', 'c']
assert letters[np.array([1, 1])] == ['b', 'b']Iterable indexing returns a list because requested positions may repeat. A slice returns an `OrderedSet` instead.
Resolve several values to positions lookup-many-indices
from ordered_set import OrderedSet
letters = OrderedSet('abracadabra')
positions = letters.index(['a', 'r', 'c'])
assert positions == [0, 2, 3]A missing member raises during the lookup. Validate external values first if partial results are useful.
Apply set algebra without losing left order set-operations
from ordered_set import OrderedSet
left = OrderedSet(['a', 'b', 'c'])
assert left | ['c', 'd'] == ['a', 'b', 'c', 'd']
assert left & {'a', 'c'} == ['a', 'c']
assert left - {'b'} == ['a', 'c']A string on the right is treated as an iterable of characters, which can be surprising for multi-character values.
Choose strict or forgiving removal remove-items
from ordered_set import OrderedSet
items = OrderedSet(['a', 'b', 'c'])
items.discard('missing')
items.remove('b')
last = items.pop()`remove` raises for an absent item, `discard` does not, and each successful middle deletion reindexes later values.
Slice and reverse the sequence view slice-and-reverse
from ordered_set import OrderedSet
items = OrderedSet('abcdef')
subset = items[1:4]
backwards = list(reversed(items))
assert subset == ['b', 'c', 'd']
assert backwards[0] == 'f'A slice produces a shallow `OrderedSet`; mutable objects inside it are shared with the original.
Use pandas-compatible lookup names pandas-style-lookup
from ordered_set import OrderedSet
vocab = OrderedSet(['red', 'green', 'blue'])
assert vocab.get_loc('green') == 1
assert vocab.get_indexer(['blue', 'red']) == [2, 0]These methods are aliases for `index`; they do not reproduce the rest of the pandas Index API.
Test order-aware equality explicitly check-equality
from ordered_set import OrderedSet
items = OrderedSet([1, 2, 3])
assert items == [1, 2, 3]
assert items != [3, 2, 1]
assert items == {3, 2, 1}Sequence comparison checks order, while comparison with a plain set checks membership only.
Serialize and restore an ordered set pickle-collection
import pickle
from ordered_set import OrderedSet
original = OrderedSet(['alpha', 'beta'])
payload = pickle.dumps(original)
restored = pickle.loads(payload)
assert restored == originalOnly unpickle data from a trusted source; Python pickle can execute code during loading.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| orderly-set | PyPI | Use it when you want a currently released ordered-set package with a newer Python support range. |
| sortedcontainers | PyPI | Use `SortedSet` when values should follow sort order and removals need logarithmic behavior. |
| boltons | PyPI | Use `IndexedSet` when indexed uniqueness is one of several utility needs and deletion patterns are less append-heavy. |
More utils guides
lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

