Source code for src.trie
from enum import Enum
[docs]
class Trie():
# we want:
## search a string and return (ideally) a single string that most closely matches
## to be able to create everything in one fell swoop, not have to insert everything all at once
# however, i don't have time to do the space-optimized trie right now, and honestly it doesn't really matter
# because it's only ever going to hold like 20 strings max
# words:
## deck, did, dog, dogs, doggie, doe, do
# uncompressed
# $
# |
# d
# /|\
# e i o
# | | |\
# c d g e
# | |\
# k s g
# |
# g
# |
# i
# |
# e
# compressed
# (root)
# |
# d
# /|\
# e i o
# c d |\
# k g e
# |\
# s g
# g
# i
# e
# to insert a word = w_0 .. w_i
# traverse the tree.
# at each node n = n_0 .. n_j:
# if we fully match a child:
# follow that edge and repeat
# otherwise:
# find the last index we match, k
# redefine n := n_0 .. n_k (note by definition this is also w_0 .. w_k)
# add children n_(k+1) .. n_j and w_(k+1) .. w_i
#
[docs]
class node():
def __init__(self, depth):
self.depth = depth
self.children = {}
self.is_end = False
def __iter__(self):
yield from self.__iter_helper([])
def __iter_helper(self, prefix):
if self.is_end:
yield "".join(prefix)
for k,v in self.children.items():
yield from v.__iter_helper(prefix + [k])
[docs]
def is_match(self, word):
node = self.__match(word)
return node.is_end and node.depth == len(word)
def __match(self, word):
if self.depth >= len(word) or word[self.depth] not in self.children:
return self
else:
return self.children[word[self.depth]].__match(word)
[docs]
def search(self, word):
node = self.__match(word)
yield from node.__iter_helper([x for x in word[:node.depth]])
def __search(self, word, acc):
if self.is_end:
pass
[docs]
def add_child(self, word):
self.__add_child(word)
def __add_child(self, word):
if self.depth >= len(word):
self.is_end = True
elif word[self.depth] in self.children:
self.children[word[self.depth]].__add_child(word)
else:
newnode = Trie.node(self.depth+1)
self.children[word[self.depth]] = newnode
newnode.__add_child(word)
def __init__(self):
self.root = Trie.node(0)
def __iter__(self):
yield from self.root
def __contains__(self, word):
return self.root.is_match(word)
[docs]
def insert(self, word):
self.root.add_child(word)
[docs]
def search(self, word):
return list(self.root.search(word))
# this stuff happens if you run this as a script instead of importing it as a package
if __name__ == "__main__":
t = Trie()
words = [
"admiration",
"acute",
"assignment",
"answer",
"bottle",
"back",
"bulletin",
"bird",
"competence",
"cord",
"cousin",
"circle",
"claim",
"deck",
"did",
"dog",
"dogs",
"doggie",
"doe",
"do",
]
for x in words:
t.insert(x)
#for x in t:
# print(x)
print(len(t.search("doreimi")))
for x in t.search(""):
print(x)