Skip to main content

A minimal type-safe trie (prefix tree) implementation in Python.

Project description

TinyTrie

A minimal and type-safe trie (prefix tree) implementation for Python 2+.

Features

  • Typed: Works with arbitrary key and value types (Generic[K, V])
  • Minimal: Only essential functionalities
  • Efficient: Memory-efficient with __slots__
  • Iterable: Easily traverse and list all stored sequences
  • No external dependencies (except typing on Python <3.5)

Basic Operations

from tinytrie import *

# Create a trie with character (`str`) keys and integer values
root = TrieNode[str, int]()

# Insert some words with values
update(root, 'apple', 1)
update(root, 'app', 2)
update(root, 'banana', 3)
update(root, 'band', 4)

# Search for existing words
assert search(root, 'apple').value == 1
assert search(root, 'app').value == 2
assert search(root, 'banana').value == 3

# Search for non-existent words
assert search(root, 'orange') is None
assert search(root, 'appetizer') is None

update(root, 'apple', 10)
assert search(root, 'apple').value == 10  # Value updated

# Insert a new word
update(root, 'orange', 5)
assert search(root, 'orange').value == 5

# Delete 'apple', 'app' remains
assert delete(root, 'apple') is True
assert search(root, 'apple') is None
assert delete(root, 'apple') is False
assert search(root, 'app') is not None

# Add back 'apple', delete 'app', 'apple' remains
update(root, 'apple', 10)
assert delete(root, 'app') is True
assert search(root, 'app') is None
assert delete(root, 'app') is False
assert search(root, 'apple') is not None

# Try to delete non-existent words
assert delete(root, 'ban') is False
assert delete(root, 'appetizer') is False

# Get common prefix from root (no common prefix)
prefix, _ = longest_common_prefix(root)
assert prefix == []  # No common prefix among all words

# Get common prefix from 'b' subtrie
subtrie_prefix = ['b']
b_subtrie_root = get_subtrie_root(root, subtrie_prefix)
prefix, _ = longest_common_prefix(b_subtrie_root)
assert prefix == ['a', 'n']  # Common between 'banana' and 'band' after 'b'

# Get all words in the trie
words = {''.join(s) for s, _ in collect_sequences(root)}
assert words == {'apple', 'banana', 'band', 'orange'}

# Get all words in the 'ba' subtrie
subtrie_prefix = ['b', 'a']
ba_subtrie_root = get_subtrie_root(root, subtrie_prefix)
words_starting_with_ba = {''.join(s) for s, _ in collect_sequences(ba_subtrie_root, prefix=subtrie_prefix)}
assert words_starting_with_ba == {'banana', 'band'}

Non-String Keys Example

from tinytrie import *

# Create a trie with tuple keys
trajectory_trie = TrieNode[Tuple[int, int], str]()
update(trajectory_trie, [(1, 2), (3, 4)], 'traj1')
update(trajectory_trie, [(1, 2), (5, 6)], 'traj2')

assert search(trajectory_trie, [(1, 2), (3, 4)]).value == 'traj1'
assert search(trajectory_trie, [(1, 2), (5, 6)]).value == 'traj2'
assert search(trajectory_trie, [(1, 2)]) is None  # Partial path

prefix, _ = longest_common_prefix(trajectory_trie)
assert prefix == [(1, 2)]

API Reference

Function Purpose Time Complexity
traverse(root: TrieNode[K, V], path: Iterable[K]) -> Iterator[Tuple[Optional[TrieNode[K, V]], K]] Yields nodes and keys along a path of keys (even if it diverges) O(n)
get_subtrie_root(root: TrieNode[K, V], path: Iterable[K]) -> Optional[TrieNode[K, V]] Gets the root node of a subtrie at the end of a path of keys if it exists O(n)
search(root: TrieNode[K, V], sequence: Iterable[K]) -> Optional[TrieNode[K, V]] Returns terminal node if sequence is stored in the trie O(n)
update(root: TrieNode[K, V], sequence: Iterable[K], value: Optional[V] = None) -> TrieNode[K, V] Inserts or updates a sequence and sets its value O(n)
delete(root: TrieNode[K, V], sequence: Sequence[K]) -> bool Removes a sequence and prunes dead nodes O(n)
longest_common_prefix(root: TrieNode[K, V]) -> Tuple[Sequence[K], TrieNode[K, V]] Finds the longest common prefix of all sequences and its terminal node O(m)
collect_sequences(root: TrieNode[K, V], prefix: Optional[List[K]] = None) -> Iterator[Tuple[List[K], TrieNode[K, V]]] Yields all stored sequences and their terminal nodes O(n) per sequence

Contributing

Contributions are welcome! Please submit pull requests or open issues on the GitHub repository.

License

This project is licensed under the MIT License.

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

tinytrie-0.1.0a7.tar.gz (5.7 kB view details)

Uploaded Source

Built Distribution

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

tinytrie-0.1.0a7-py2.py3-none-any.whl (6.1 kB view details)

Uploaded Python 2Python 3

File details

Details for the file tinytrie-0.1.0a7.tar.gz.

File metadata

  • Download URL: tinytrie-0.1.0a7.tar.gz
  • Upload date:
  • Size: 5.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for tinytrie-0.1.0a7.tar.gz
Algorithm Hash digest
SHA256 8eedb53a1dcf904bd67a70cf95708aad592997646df902b444d3f6946c50bb83
MD5 01ac1497f2eed97fc6b510450cf6650d
BLAKE2b-256 46b2e481d022d1e05a5d08f58bf3d75fdfe2258de333184e99ef066545510f3d

See more details on using hashes here.

File details

Details for the file tinytrie-0.1.0a7-py2.py3-none-any.whl.

File metadata

  • Download URL: tinytrie-0.1.0a7-py2.py3-none-any.whl
  • Upload date:
  • Size: 6.1 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for tinytrie-0.1.0a7-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 7955d7ea9ab7bdb5c00a6c53ddbf046dd717d53a2342f772de898b25b2a829e0
MD5 d789b3b94316253c30137af7ecbe4ee8
BLAKE2b-256 eed24b0a167f6e5b3717f0a55e1487b9c69a60bc52f13012644ecad027f4cd36

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