serverless-spy
Version:
CDK-based library for writing elegant integration tests on AWS serverless architecture and an additional web console to monitor events in real time.
181 lines (146 loc) • 3.28 kB
JavaScript
/* eslint no-constant-condition: 0 */
/**
* Mnemonist BK Tree
* ==================
*
* Implementation of a Burkhard-Keller tree, allowing fast lookups of words
* that lie within a specified distance of the query word.
*
* [Reference]:
* https://en.wikipedia.org/wiki/BK-tree
*
* [Article]:
* W. Burkhard and R. Keller. Some approaches to best-match file searching,
* CACM, 1973
*/
var forEach = require('obliterator/foreach');
/**
* BK Tree.
*
* @constructor
* @param {function} distance - Distance function to use.
*/
function BKTree(distance) {
if (typeof distance !== 'function')
throw new Error('mnemonist/BKTree.constructor: given `distance` should be a function.');
this.distance = distance;
this.clear();
}
/**
* Method used to add an item to the tree.
*
* @param {any} item - Item to add.
* @return {BKTree}
*/
BKTree.prototype.add = function(item) {
// Initializing the tree with the first given word
if (!this.root) {
this.root = {
item: item,
children: {}
};
this.size++;
return this;
}
var node = this.root,
d;
while (true) {
d = this.distance(item, node.item);
if (!node.children[d])
break;
node = node.children[d];
}
node.children[d] = {
item: item,
children: {}
};
this.size++;
return this;
};
/**
* Method used to query the tree.
*
* @param {number} n - Maximum distance between query & item.
* @param {any} query - Query
* @return {BKTree}
*/
BKTree.prototype.search = function(n, query) {
if (!this.root)
return [];
var found = [],
stack = [this.root],
node,
child,
d,
i,
l;
while (stack.length) {
node = stack.pop();
d = this.distance(query, node.item);
if (d <= n)
found.push({item: node.item, distance: d});
for (i = d - n, l = d + n + 1; i < l; i++) {
child = node.children[i];
if (child)
stack.push(child);
}
}
return found;
};
/**
* Method used to clear the tree.
*
* @return {undefined}
*/
BKTree.prototype.clear = function() {
// Properties
this.size = 0;
this.root = null;
};
/**
* Convenience known methods.
*/
BKTree.prototype.toJSON = function() {
return this.root;
};
BKTree.prototype.inspect = function() {
var array = [],
stack = [this.root],
node,
d;
while (stack.length) {
node = stack.pop();
if (!node)
continue;
array.push(node.item);
for (d in node.children)
stack.push(node.children[d]);
}
// Trick so that node displays the name of the constructor
Object.defineProperty(array, 'constructor', {
value: BKTree,
enumerable: false
});
return array;
};
if (typeof Symbol !== 'undefined')
BKTree.prototype[Symbol.for('nodejs.util.inspect.custom')] = BKTree.prototype.inspect;
/**
* Static @.from function taking an arbitrary iterable & converting it into
* a tree.
*
* @param {Iterable} iterable - Target iterable.
* @param {function} distance - Distance function.
* @return {Heap}
*/
BKTree.from = function(iterable, distance) {
var tree = new BKTree(distance);
forEach(iterable, function(value) {
tree.add(value);
});
return tree;
};
/**
* Exporting.
*/
module.exports = BKTree;