Mnemonist

Trie


The trie - pronounced like in re•trie•val - is a kind tree very useful to work with prefixes.

For more information about the Trie, you can head here.

const Trie = require('mnemonist/trie');

Use case

Let’s say we have a list of strings and we want to be able to find them by a given prefix:

const words = [
  'roman',
  'romanesque',
  'romanesco',
  'cat',
  'category'
];

A naive approach would be to compare each of our strings with the given prefix to find the matching ones:

words.forEach((word) => {
  if (word.startsWith(query))
    console.log('Matching prefix!', word);
});

Even if this approach is perfectly fine, we are going to need O(n) computations to find the matching words.

A trie, on the contrary, is able to answer this kind of query more efficiently:

// Let's create a trie from our words
const trie = Trie.from(words);

// Now let's query our trie
const wordsWithMatchingPrefix = trie.find(query);

Constructor

The Trie optionally takes as single argument the type of sequence you are going to feed it.

// For a trie containing string prefixes
const trie = new Trie();
// For a trie containing arbitrary sequences fed as arrays
const trie = new Trie(Array);

Static #.from

Alternatively, one can build a Trie from an arbitrary JavaScript iterable likewise:

const trie = Trie.from(['roman', 'romanesque']);

Members

Methods

Mutation

Read

Iteration

#.size

Number of prefixes in the trie.

const trie = new Trie();
trie.size
>>> 0

#.add

Adds a prefix into the Trie. If the prefix is a string, it will be split into characters. Else, you can provide an array of custom tokens.

O(m), m being the size of the inserted string.

const trie = new Trie();
trie.add('hello');

trie.has('hello');
>>> true

// Using custom tokens
trie.add(['I', 'am', 'very', 'happy']);

#.delete

Deletes a prefix from the Trie. Returns true if the prefix was deleted & false if the prefix was not in the Trie.

O(m), m being the size of the deleted string.

const trie = new Trie();
trie.add('hello');

trie.delete('hello');
>>> true

trie.delete('world');
>>> false

#.clear

Completely clears the trie.

const trie = new Trie();
trie.add('hello');
trie.add('roman');

trie.clear();

trie.size
>>> 0

#.has

Returns whether the given prefix exists in the trie.

O(m), m being the size of the searched string.

const trie = new Trie();
trie.add('hello');

trie.has('hello');
>>> true

trie.has('world');
>>> false

#.find

Returns an array of every prefixes found in the trie with the given prefix.

O(m + n), m being the size of the query, n being the cumulated size of the matched prefixes.

const trie = new Trie();
trie.add('roman');
trie.add('romanesque');
trie.add('greek');

trie.find('rom');
>>> ['roman', 'romanesque']

trie.find('gr');
>>> ['greek']

trie.find('hel');
>>> []

#.keys

Alias of #.prefixes.

#.prefixes

Returns an iterator over the trie’s prefixes (note that the order on which the trie will iterate over its prefixes is arbitrary).

const trie = Trie.from(['roman', 'romanesque']);

const iterator = trie.prefixes();

iterator.next().value
>>> 'roman'

Iterable

Alternatively, you can iterate over a trie’s prefixes using ES2015 for...of protocol:

const trie = Trie.from(['roman', 'romanesque']);

for (const prefix of trie) {
  console.log(prefix);
}