|
|
|
// ref : https://medium.com/weekly-webtips/js-implementing-auto-complete-f4c5a5d5c009
|
|
|
|
|
|
|
|
interface Node {
|
|
|
|
value: []
|
|
|
|
isLeaf: boolean
|
|
|
|
children: Record<string, Node>
|
|
|
|
}
|
|
|
|
|
|
|
|
export class NcAutocompleteTree {
|
|
|
|
trie: Record<string, any>
|
|
|
|
suggestions: Record<string, any>[]
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
this.trie = {}
|
|
|
|
this.suggestions = []
|
|
|
|
}
|
|
|
|
|
|
|
|
newNode(): Node {
|
|
|
|
return {
|
|
|
|
value: [],
|
|
|
|
isLeaf: false,
|
|
|
|
children: {},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
add(word: Record<string, any>) {
|
|
|
|
if (Object.keys(this.trie).length === 0) {
|
|
|
|
this.trie = this.newNode()
|
|
|
|
}
|
|
|
|
|
|
|
|
let root = this.trie
|
|
|
|
for (const letter of word.text.toLowerCase()) {
|
|
|
|
if (!(letter in root.children)) {
|
|
|
|
root.children[letter] = this.newNode()
|
|
|
|
}
|
|
|
|
root = root.children[letter]
|
|
|
|
}
|
|
|
|
root.value = root.value || []
|
|
|
|
root.value.push(word)
|
|
|
|
root.isLeaf = true
|
|
|
|
}
|
|
|
|
|
|
|
|
find(word: string) {
|
|
|
|
let root = this.trie
|
|
|
|
for (const letter of word) {
|
|
|
|
if (letter in root.children) {
|
|
|
|
root = root.children[letter]
|
|
|
|
} else {
|
|
|
|
return null // if not found return null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return root // return the root where it ends search
|
|
|
|
}
|
|
|
|
|
|
|
|
traverse(root: Node) {
|
|
|
|
if (root.isLeaf) {
|
|
|
|
this.suggestions.push(...root.value)
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const letter in root.children) {
|
|
|
|
this.traverse(root.children[letter])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
complete(word: string, CHILDREN = null) {
|
|
|
|
this.suggestions = []
|
|
|
|
const root = this.find(word.toLowerCase())
|
|
|
|
|
|
|
|
if (!root) {
|
|
|
|
return this.suggestions
|
|
|
|
} // cannot suggest anything
|
|
|
|
|
|
|
|
this.suggestions.push(...root.value)
|
|
|
|
|
|
|
|
const children = root.children
|
|
|
|
|
|
|
|
let spread = 0
|
|
|
|
for (const letter in children) {
|
|
|
|
this.traverse(children[letter])
|
|
|
|
spread++
|
|
|
|
|
|
|
|
if (CHILDREN && spread === CHILDREN) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.suggestions
|
|
|
|
}
|
|
|
|
}
|