# Mnemonist

## Fuzzy MultiMap

The `FuzzyMultiMap` is basically a `FuzzyMap` that accepts more than one value per key and stores the colliding items in buckets.

``````const FuzzyMultiMap = require('mnemonist/fuzzy-multi-map');
``````

## Use case

Let’s say we need to store items in an index using a fuzzy key so that we may match them against not so precise queries.

Furthermore, since the key produced might be the same for several items and because we want to keep multiple values for each key, we could use a `FuzzyMultiMap` to help us in this task.

``````// Using lodash to create a naive fuzzy key using the given title
function fuzzyTitle(title) {
return _.words(title.toLowerCase()).sort().join(' ');
}

// Creating our index
const map = new FuzzyMultiMap(fuzzyTitle);

const universities = [
{name: 'University of Carolina'},
{name: 'Carolina, university of.'},
{name: 'Harvard university'}
];

universities.forEach((university) => {
map.set(university.name, university)
});

// Now we can query the index
universities.get('university of carolina');
>>> [
{name: 'University of Carolina'},
{name: 'Carolina, university of.'}
]
``````

## Constructor

The `FuzzyMultiMap` either takes a single argument being a hash function that will process both inserted items or keys & the queries; or a tuple containing two hash functions, one for the inserted items or keys and the second one for the queries.

As with the MultiMap, the `FuzzyMultiMap` can also take a container as second argument.

Example with one hash function

``````// Let's create an index using a single hash function:
const map = new FuzzyMultiMap((value) => value.toUpperCase());

// Then you'll probably use #.set to insert items
map.set(movie.title, movie);
map.get(queryTitle);
``````

Example with two hash functions

``````// Let's create an index using two different hash functions:
const map = new FuzzyMultiMap([

// Hash function for inserted items:
(movie) => movie.title.toLowerCase(),

// Hash function for queries
(query) => query.toLowerCase(),
]);

// Then you'll probably use #.add to insert items
map.get(queryTitle);
``````

Example with Set containers

``````const map = new FuzzyMultiMap((value) => value.toUpperCase(), Set);
``````

Warning!: the index will not consider any falsy key processed by its hash functions.

``````const map = new FuzzyMultiMap((item) => item.title && item.title.toLowerCase());

const movie = {year: 1999};

// This will not be indexed on `undefined`
map.set(movie.title, movie);
``````

### Static #.from

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

``````const map = FuzzyMultiMap.from(list, hashFunctions);
``````
``````const map = FuzzyMultiMap.from(list, hashFunctions, Container);
``````

## Methods

Mutation

Iteration

### #.dimension

Number of item containers stored in the map.

``````const map = new FuzzyMultiMap();
map.set('hello', 3);
map.set('hello', 4);

map.size
>>> 2
map.dimension
>>> 1
``````

### #.size

Number of items stored in the map.

``````const map = new FuzzyMultiMap();

map.size
>>> 1
``````

Computes the item’s key by hashing the given item using the relevant function then adds the item to the map using the key.

`O(1)`

``````const map = new FuzzyMultiMap();

// In fact, same as doing
const movie = {title: 'Great movie', year: 1999};
map.set(movie, movie);
``````

### #.set

Adds an item to the map using the provided key that will be processed by the relevant hash function.

`O(1)`

``````const map = new FuzzyMultiMap();
const movie = {title: 'Great movie', year: 1999};

map.set(movie.title, movie);
``````

Completely clears the map of its items.

``````const map = new FuzzyMultiMap();
map.clear();

map.size
>>> 0
``````

### #.get

Hash the given key using the relevant function then returns the set of items stored by this key.

`O(1)`

``````const map = new FuzzyMultiMap((string) => string.toLowerCase());
map.set('John', {name: 'John', surname: 'Williams'});
map.set('John', {name: 'John', surname: 'Ableton'});

map.get('john');
>>> [
{name: 'John', surname: 'Williams'},
{name: 'John', surname: 'Ableton'}
]
``````

### #.has

Test whether the provided key, processed by the relevant hash function, would return a container.

`O(1)`

``````const map = new FuzzyMultiMap((string) => string.toLowerCase());
map.set('John', {name: 'John', surname: 'Williams'});
map.set('John', {name: 'John', surname: 'Ableton'});

map.get('john');
>>> true
``````

### #.forEach

Iterates over the values stored in the map.

``````const map = new FuzzyMultiMap((string) => string.toLowerCase());

map.set('John', {name: 'John', surname: 'Williams'});
map.set('John', {name: 'John', surname: 'Ableton'});

map.forEach((value) => {
console.log(value);
});
>>> {name: 'John', surname: 'Williams'}
>>> {name: 'John', surname: 'Ableton'}
``````

### #.values

Creates an iterator over the map’s values.

``````const map = new FuzzyMultiMap((string) => string.toLowerCase());

map.set('John', {name: 'John', surname: 'Williams'});
map.set('John', {name: 'John', surname: 'Ableton'});

const iterator = map.values();
iterator.next().value();
>>> {name: 'John', surname: 'Williams'}
``````

### Iterable

Alternatively, you can iterate over an map’ values using ES2015 `for...of` protocol:

``````const map = new FuzzyMultiMap((string) => string.toLowerCase());

map.set('John', {name: 'John', surname: 'Williams'});
map.set('John', {name: 'John', surname: 'Ableton'});

for (const  value of map) {
console.log(value);
}
``````