You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					446 lines
				
				8.9 KiB
			
		
		
			
		
	
	
					446 lines
				
				8.9 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Mnemonist MultiSet
							 | 
						||
| 
								 | 
							
								 * ====================
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * JavaScript implementation of a MultiSet.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								var Iterator = require('obliterator/iterator'),
							 | 
						||
| 
								 | 
							
								    forEach = require('obliterator/foreach'),
							 | 
						||
| 
								 | 
							
								    FixedReverseHeap = require('./fixed-reverse-heap.js');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Helpers.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								var MULTISET_ITEM_COMPARATOR = function(a, b) {
							 | 
						||
| 
								 | 
							
								  if (a[1] > b[1])
							 | 
						||
| 
								 | 
							
								    return -1;
							 | 
						||
| 
								 | 
							
								  if (a[1] < b[1])
							 | 
						||
| 
								 | 
							
								    return 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return 0;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// TODO: helper functions: union, intersection, sum, difference, subtract
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * MultiSet.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @constructor
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function MultiSet() {
							 | 
						||
| 
								 | 
							
								  this.items = new Map();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  Object.defineProperty(this.items, 'constructor', {
							 | 
						||
| 
								 | 
							
								    value: MultiSet,
							 | 
						||
| 
								 | 
							
								    enumerable: false
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.clear();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to clear the structure.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @return {undefined}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								MultiSet.prototype.clear = function() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Properties
							 | 
						||
| 
								 | 
							
								  this.size = 0;
							 | 
						||
| 
								 | 
							
								  this.dimension = 0;
							 | 
						||
| 
								 | 
							
								  this.items.clear();
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to add an item to the set.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {any}    item  - Item to add.
							 | 
						||
| 
								 | 
							
								 * @param  {number} count - Optional count.
							 | 
						||
| 
								 | 
							
								 * @return {MultiSet}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								MultiSet.prototype.add = function(item, count) {
							 | 
						||
| 
								 | 
							
								  if (count === 0)
							 | 
						||
| 
								 | 
							
								    return this;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (count < 0)
							 | 
						||
| 
								 | 
							
								    return this.remove(item, -count);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  count = count || 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (typeof count !== 'number')
							 | 
						||
| 
								 | 
							
								    throw new Error('mnemonist/multi-set.add: given count should be a number.');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.size += count;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const currentCount = this.items.get(item);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (currentCount === undefined)
							 | 
						||
| 
								 | 
							
								    this.dimension++;
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    count += currentCount;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.items.set(item, count);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return this;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to set the multiplicity of an item in the set.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {any}    item  - Target item.
							 | 
						||
| 
								 | 
							
								 * @param  {number} count - Desired multiplicity.
							 | 
						||
| 
								 | 
							
								 * @return {MultiSet}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								MultiSet.prototype.set = function(item, count) {
							 | 
						||
| 
								 | 
							
								  var currentCount;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (typeof count !== 'number')
							 | 
						||
| 
								 | 
							
								    throw new Error('mnemonist/multi-set.set: given count should be a number.');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Setting an item to 0 or to a negative number means deleting it from the set
							 | 
						||
| 
								 | 
							
								  if (count <= 0) {
							 | 
						||
| 
								 | 
							
								    currentCount = this.items.get(item);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (typeof currentCount !== 'undefined') {
							 | 
						||
| 
								 | 
							
								      this.size -= currentCount;
							 | 
						||
| 
								 | 
							
								      this.dimension--;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    this.items.delete(item);
							 | 
						||
| 
								 | 
							
								    return this;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  count = count || 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  currentCount = this.items.get(item);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (typeof currentCount === 'number') {
							 | 
						||
| 
								 | 
							
								    this.items.set(item, currentCount + count);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  else {
							 | 
						||
| 
								 | 
							
								    this.dimension++;
							 | 
						||
| 
								 | 
							
								    this.items.set(item, count);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.size += count;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return this;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to return whether the item exists in the set.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {any} item  - Item to check.
							 | 
						||
| 
								 | 
							
								 * @return {boolan}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								MultiSet.prototype.has = function(item) {
							 | 
						||
| 
								 | 
							
								  return this.items.has(item);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to delete an item from the set.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {any} item  - Item to delete.
							 | 
						||
| 
								 | 
							
								 * @return {boolan}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								MultiSet.prototype.delete = function(item) {
							 | 
						||
| 
								 | 
							
								  var count = this.items.get(item);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (count === 0)
							 | 
						||
| 
								 | 
							
								    return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.size -= count;
							 | 
						||
| 
								 | 
							
								  this.dimension--;
							 | 
						||
| 
								 | 
							
								  this.items.delete(item);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return true;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to remove an item from the set.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {any} item  - Item to delete.
							 | 
						||
| 
								 | 
							
								 * @param  {number} count - Optional count.
							 | 
						||
| 
								 | 
							
								 * @return {undefined}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								MultiSet.prototype.remove = function(item, count) {
							 | 
						||
| 
								 | 
							
								  if (count === 0)
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (count < 0)
							 | 
						||
| 
								 | 
							
								    return this.add(item, -count);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  count = count || 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (typeof count !== 'number')
							 | 
						||
| 
								 | 
							
								    throw new Error('mnemonist/multi-set.remove: given count should be a number.');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var currentCount = this.items.get(item);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (typeof currentCount === 'undefined') return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var newCount = Math.max(0, currentCount - count);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (newCount === 0) {
							 | 
						||
| 
								 | 
							
								    this.items.delete(item);
							 | 
						||
| 
								 | 
							
								    this.size -= currentCount;
							 | 
						||
| 
								 | 
							
								    this.dimension--;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  else {
							 | 
						||
| 
								 | 
							
								    this.items.set(item, newCount);
							 | 
						||
| 
								 | 
							
								    this.size -= count;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to change a key into another one, merging counts if the target
							 | 
						||
| 
								 | 
							
								 * key already exists.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {any} a - From key.
							 | 
						||
| 
								 | 
							
								 * @param  {any} b - To key.
							 | 
						||
| 
								 | 
							
								 * @return {MultiSet}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								MultiSet.prototype.edit = function(a, b) {
							 | 
						||
| 
								 | 
							
								  var am = this.multiplicity(a);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // If a does not exist in the set, we can stop right there
							 | 
						||
| 
								 | 
							
								  if (am === 0)
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var bm = this.multiplicity(b);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.items.set(b, am + bm);
							 | 
						||
| 
								 | 
							
								  this.items.delete(a);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return this;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to return the multiplicity of the given item.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {any} item  - Item to get.
							 | 
						||
| 
								 | 
							
								 * @return {number}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								MultiSet.prototype.multiplicity = function(item) {
							 | 
						||
| 
								 | 
							
								  var count = this.items.get(item);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (typeof count === 'undefined')
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return count;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								MultiSet.prototype.get = MultiSet.prototype.multiplicity;
							 | 
						||
| 
								 | 
							
								MultiSet.prototype.count = MultiSet.prototype.multiplicity;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to return the frequency of the given item in the set.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {any} item - Item to get.
							 | 
						||
| 
								 | 
							
								 * @return {number}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								MultiSet.prototype.frequency = function(item) {
							 | 
						||
| 
								 | 
							
								  if (this.size === 0)
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var count = this.multiplicity(item);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return count / this.size;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to return the n most common items from the set.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {number} n - Number of items to retrieve.
							 | 
						||
| 
								 | 
							
								 * @return {array}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								MultiSet.prototype.top = function(n) {
							 | 
						||
| 
								 | 
							
								  if (typeof n !== 'number' || n <= 0)
							 | 
						||
| 
								 | 
							
								    throw new Error('mnemonist/multi-set.top: n must be a number > 0.');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var heap = new FixedReverseHeap(Array, MULTISET_ITEM_COMPARATOR, n);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var iterator = this.items.entries(),
							 | 
						||
| 
								 | 
							
								      step;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while ((step = iterator.next(), !step.done))
							 | 
						||
| 
								 | 
							
								    heap.push(step.value);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return heap.consume();
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to iterate over the set's values.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {function}  callback - Function to call for each item.
							 | 
						||
| 
								 | 
							
								 * @param  {object}    scope    - Optional scope.
							 | 
						||
| 
								 | 
							
								 * @return {undefined}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								MultiSet.prototype.forEach = function(callback, scope) {
							 | 
						||
| 
								 | 
							
								  scope = arguments.length > 1 ? scope : this;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.items.forEach(function(multiplicity, value) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (i = 0; i < multiplicity; i++)
							 | 
						||
| 
								 | 
							
								      callback.call(scope, value, value);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to iterate over the set's multiplicities.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {function}  callback - Function to call for each multiplicity.
							 | 
						||
| 
								 | 
							
								 * @param  {object}    scope    - Optional scope.
							 | 
						||
| 
								 | 
							
								 * @return {undefined}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								MultiSet.prototype.forEachMultiplicity = function(callback, scope) {
							 | 
						||
| 
								 | 
							
								  scope = arguments.length > 1 ? scope : this;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.items.forEach(callback, scope);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method returning an iterator over the set's keys. I.e. its unique values,
							 | 
						||
| 
								 | 
							
								 * in a sense.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @return {Iterator}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								MultiSet.prototype.keys = function() {
							 | 
						||
| 
								 | 
							
								  return this.items.keys();
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method returning an iterator over the set's values.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @return {Iterator}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								MultiSet.prototype.values = function() {
							 | 
						||
| 
								 | 
							
								  var iterator = this.items.entries(),
							 | 
						||
| 
								 | 
							
								      inContainer = false,
							 | 
						||
| 
								 | 
							
								      step,
							 | 
						||
| 
								 | 
							
								      value,
							 | 
						||
| 
								 | 
							
								      multiplicity,
							 | 
						||
| 
								 | 
							
								      i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return new Iterator(function next() {
							 | 
						||
| 
								 | 
							
								    if (!inContainer) {
							 | 
						||
| 
								 | 
							
								      step = iterator.next();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (step.done)
							 | 
						||
| 
								 | 
							
								        return {done: true};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      inContainer = true;
							 | 
						||
| 
								 | 
							
								      value = step.value[0];
							 | 
						||
| 
								 | 
							
								      multiplicity = step.value[1];
							 | 
						||
| 
								 | 
							
								      i = 0;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (i >= multiplicity) {
							 | 
						||
| 
								 | 
							
								      inContainer = false;
							 | 
						||
| 
								 | 
							
								      return next();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    i++;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return {
							 | 
						||
| 
								 | 
							
								      done: false,
							 | 
						||
| 
								 | 
							
								      value: value
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method returning an iterator over the set's multiplicities.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @return {Iterator}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								MultiSet.prototype.multiplicities = function() {
							 | 
						||
| 
								 | 
							
								  return this.items.entries();
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Attaching the #.entries method to Symbol.iterator if possible.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								if (typeof Symbol !== 'undefined')
							 | 
						||
| 
								 | 
							
								  MultiSet.prototype[Symbol.iterator] = MultiSet.prototype.values;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Convenience known methods.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								MultiSet.prototype.inspect = function() {
							 | 
						||
| 
								 | 
							
								  return this.items;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if (typeof Symbol !== 'undefined')
							 | 
						||
| 
								 | 
							
								  MultiSet.prototype[Symbol.for('nodejs.util.inspect.custom')] = MultiSet.prototype.inspect;
							 | 
						||
| 
								 | 
							
								MultiSet.prototype.toJSON = function() {
							 | 
						||
| 
								 | 
							
								  return this.items;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Static @.from function taking an arbitrary iterable & converting it into
							 | 
						||
| 
								 | 
							
								 * a structure.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {Iterable} iterable - Target iterable.
							 | 
						||
| 
								 | 
							
								 * @return {MultiSet}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								MultiSet.from = function(iterable) {
							 | 
						||
| 
								 | 
							
								  var set = new MultiSet();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  forEach(iterable, function(value) {
							 | 
						||
| 
								 | 
							
								    set.add(value);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return set;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Function returning whether the multiset A is a subset of the multiset B.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {MultiSet} A - First set.
							 | 
						||
| 
								 | 
							
								 * @param  {MultiSet} B - Second set.
							 | 
						||
| 
								 | 
							
								 * @return {boolean}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								MultiSet.isSubset = function(A, B) {
							 | 
						||
| 
								 | 
							
								  var iterator = A.multiplicities(),
							 | 
						||
| 
								 | 
							
								      step,
							 | 
						||
| 
								 | 
							
								      key,
							 | 
						||
| 
								 | 
							
								      mA;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Shortcuts
							 | 
						||
| 
								 | 
							
								  if (A === B)
							 | 
						||
| 
								 | 
							
								    return true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (A.dimension > B.dimension)
							 | 
						||
| 
								 | 
							
								    return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while ((step = iterator.next(), !step.done)) {
							 | 
						||
| 
								 | 
							
								    key = step.value[0];
							 | 
						||
| 
								 | 
							
								    mA = step.value[1];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (B.multiplicity(key) < mA)
							 | 
						||
| 
								 | 
							
								      return false;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return true;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Function returning whether the multiset A is a superset of the multiset B.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {MultiSet} A - First set.
							 | 
						||
| 
								 | 
							
								 * @param  {MultiSet} B - Second set.
							 | 
						||
| 
								 | 
							
								 * @return {boolean}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								MultiSet.isSuperset = function(A, B) {
							 | 
						||
| 
								 | 
							
								  return MultiSet.isSubset(B, A);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Exporting.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								module.exports = MultiSet;
							 |