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.0a6.tar.gz (5.6 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.0a6-py2.py3-none-any.whl (6.0 kB view details)

Uploaded Python 2Python 3

File details

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

File metadata

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

File hashes

Hashes for tinytrie-0.1.0a6.tar.gz
Algorithm Hash digest
SHA256 d9958b8d51166b36c33f0ddee745679c53eaaf6409db77818a9c639453ee0620
MD5 d001b92c1773c17973ff0626a188d045
BLAKE2b-256 4e43f5ddc0a95f462c3230aca037fbcb717d32013539b7310b61e481a52059c2

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for tinytrie-0.1.0a6-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 620038b3b4d3094e86835754c6cd6f771d01d9438caeab8bb1c163be5731ca23
MD5 25c8de80f8cfcff19637096f0dfc8cbc
BLAKE2b-256 6bed74677e8a97e58a15791cdb15b9abe28c2432e1967cd3a803bd4ff4c803c3

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