Skip to content

Instantly share code, notes, and snippets.

@AugmentedFifth
Created May 7, 2017 02:52
Show Gist options
  • Save AugmentedFifth/5f48bea2d3a15049b9b441ab105e49d5 to your computer and use it in GitHub Desktop.
Save AugmentedFifth/5f48bea2d3a15049b9b441ab105e49d5 to your computer and use it in GitHub Desktop.
function Trie(valueCons, hasValue=false) {
"use strict";
const constructorFailure = new TypeError(
"Tries must be initialized with a valid constructor " +
"of an iterable type as the first argument."
);
if (typeof valueCons !== "function") {
throw constructorFailure;
}
try {
const val = new valueCons();
if (typeof val[Symbol.iterator] !== "function") {
throw 0;
}
} catch (_) {
throw constructorFailure;
}
this.hasValue = hasValue;
this.children = new Map();
this.valueCons = valueCons;
this.setValue = function(hasValue) {
this.hasValue = hasValue;
};
this.hasChild = function(elem) {
return this.children.has(elem);
};
this.getChild = function(elem) {
return this.children.get(elem);
};
this.addChild = function(elem, child) {
this.children.set(elem, child);
};
this.add = function(newVal) {
if (
!(
newVal instanceof valueCons ||
valueCons === String && typeof newVal === "string"
)
) {
throw new TypeError(
"Attempted to add a value of mismatched type to Trie.\n" +
"Expected type: " +
this.valueCons +
"\nGot this value: " +
newVal
);
}
let node = this;
for (const elem of newVal) {
if (node.hasChild(elem)) {
node = node.getChild(elem);
} else {
const newChild = new Trie(this.valueCons);
node.addChild(elem, newChild);
node = newChild;
}
}
node.setValue(true);
};
this.allValues = function() {
const values = [];
if (this.hasValue) {
values.push(new valueCons());
}
this.children.forEach((child, elem) => {
child.allValues().forEach(childVal => {
values.push(elem.concat(childVal));
});
});
return values;
};
this.contains = function(needle) {
if (
!(
needle instanceof valueCons ||
valueCons === String && typeof needle === "string"
)
) {
throw new TypeError(
"Attempted to search for a value of mismatched type in a Trie.\n" +
"Expected type: " +
this.valueCons +
"\nGot this value: " +
needle
);
}
let node = this;
for (const elem of needle) {
if (!node.hasChild(elem)) {
return false;
}
node = node.getChild(elem);
}
return node.hasValue;
};
this.getPrefixCompletions = function(prefix) {
if (
!(
prefix instanceof valueCons ||
valueCons === String && typeof prefix === "string"
)
) {
throw new TypeError(
"Attempted to get completions for prefix of mismatched type in Trie.\n" +
"Expected type: " +
this.valueCons +
"\nGot this value: " +
prefix
);
}
let node = this;
for (const elem of prefix) {
node = node.getChild(elem);
if (!node) {
return [];
}
}
return node.allValues();
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment