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.
		
		
		
		
		
			
		
			
				
					564 lines
				
				11 KiB
			
		
		
			
		
	
	
					564 lines
				
				11 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								/* eslint no-constant-condition: 0 */
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Mnemonist Merge Helpers
							 | 
						||
| 
								 | 
							
								 * ========================
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Various merge algorithms used to handle sorted lists. Note that the given
							 | 
						||
| 
								 | 
							
								 * functions are optimized and won't accept mixed arguments.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Note: maybe this piece of code belong to sortilege, along with binary-search.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								var typed = require('./typed-arrays.js'),
							 | 
						||
| 
								 | 
							
								    isArrayLike = require('./iterables.js').isArrayLike,
							 | 
						||
| 
								 | 
							
								    binarySearch = require('./binary-search.js'),
							 | 
						||
| 
								 | 
							
								    FibonacciHeap = require('../fibonacci-heap.js');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// TODO: update to use exponential search
							 | 
						||
| 
								 | 
							
								// TODO: when not knowing final length => should use plain arrays rather than
							 | 
						||
| 
								 | 
							
								// same type as input
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Merge two sorted array-like structures into one.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {array} a - First array.
							 | 
						||
| 
								 | 
							
								 * @param  {array} b - Second array.
							 | 
						||
| 
								 | 
							
								 * @return {array}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function mergeArrays(a, b) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // One of the arrays is empty
							 | 
						||
| 
								 | 
							
								  if (a.length === 0)
							 | 
						||
| 
								 | 
							
								    return b.slice();
							 | 
						||
| 
								 | 
							
								  if (b.length === 0)
							 | 
						||
| 
								 | 
							
								    return a.slice();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Finding min array
							 | 
						||
| 
								 | 
							
								  var tmp;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (a[0] > b[0]) {
							 | 
						||
| 
								 | 
							
								    tmp = a;
							 | 
						||
| 
								 | 
							
								    a = b;
							 | 
						||
| 
								 | 
							
								    b = tmp;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // If array have non overlapping ranges, we can just concatenate them
							 | 
						||
| 
								 | 
							
								  var aEnd = a[a.length - 1],
							 | 
						||
| 
								 | 
							
								      bStart = b[0];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (aEnd <= bStart) {
							 | 
						||
| 
								 | 
							
								    if (typed.isTypedArray(a))
							 | 
						||
| 
								 | 
							
								      return typed.concat(a, b);
							 | 
						||
| 
								 | 
							
								    return a.concat(b);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Initializing target
							 | 
						||
| 
								 | 
							
								  var array = new a.constructor(a.length + b.length);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Iterating until we overlap
							 | 
						||
| 
								 | 
							
								  var i, l, v;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (i = 0, l = a.length; i < l; i++) {
							 | 
						||
| 
								 | 
							
								    v = a[i];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (v <= bStart)
							 | 
						||
| 
								 | 
							
								      array[i] = v;
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Handling overlap
							 | 
						||
| 
								 | 
							
								  var aPointer = i,
							 | 
						||
| 
								 | 
							
								      aLength = a.length,
							 | 
						||
| 
								 | 
							
								      bPointer = 0,
							 | 
						||
| 
								 | 
							
								      bLength = b.length,
							 | 
						||
| 
								 | 
							
								      aHead,
							 | 
						||
| 
								 | 
							
								      bHead;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while (aPointer < aLength && bPointer < bLength) {
							 | 
						||
| 
								 | 
							
								    aHead = a[aPointer];
							 | 
						||
| 
								 | 
							
								    bHead = b[bPointer];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (aHead <= bHead) {
							 | 
						||
| 
								 | 
							
								      array[i++] = aHead;
							 | 
						||
| 
								 | 
							
								      aPointer++;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								      array[i++] = bHead;
							 | 
						||
| 
								 | 
							
								      bPointer++;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Filling
							 | 
						||
| 
								 | 
							
								  while (aPointer < aLength)
							 | 
						||
| 
								 | 
							
								    array[i++] = a[aPointer++];
							 | 
						||
| 
								 | 
							
								  while (bPointer < bLength)
							 | 
						||
| 
								 | 
							
								    array[i++] = b[bPointer++];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return array;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Perform the union of two already unique sorted array-like structures into one.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {array} a - First array.
							 | 
						||
| 
								 | 
							
								 * @param  {array} b - Second array.
							 | 
						||
| 
								 | 
							
								 * @return {array}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function unionUniqueArrays(a, b) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // One of the arrays is empty
							 | 
						||
| 
								 | 
							
								  if (a.length === 0)
							 | 
						||
| 
								 | 
							
								    return b.slice();
							 | 
						||
| 
								 | 
							
								  if (b.length === 0)
							 | 
						||
| 
								 | 
							
								    return a.slice();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Finding min array
							 | 
						||
| 
								 | 
							
								  var tmp;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (a[0] > b[0]) {
							 | 
						||
| 
								 | 
							
								    tmp = a;
							 | 
						||
| 
								 | 
							
								    a = b;
							 | 
						||
| 
								 | 
							
								    b = tmp;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // If array have non overlapping ranges, we can just concatenate them
							 | 
						||
| 
								 | 
							
								  var aEnd = a[a.length - 1],
							 | 
						||
| 
								 | 
							
								      bStart = b[0];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (aEnd < bStart) {
							 | 
						||
| 
								 | 
							
								    if (typed.isTypedArray(a))
							 | 
						||
| 
								 | 
							
								      return typed.concat(a, b);
							 | 
						||
| 
								 | 
							
								    return a.concat(b);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Initializing target
							 | 
						||
| 
								 | 
							
								  var array = new a.constructor();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Iterating until we overlap
							 | 
						||
| 
								 | 
							
								  var i, l, v;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (i = 0, l = a.length; i < l; i++) {
							 | 
						||
| 
								 | 
							
								    v = a[i];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (v < bStart)
							 | 
						||
| 
								 | 
							
								      array.push(v);
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Handling overlap
							 | 
						||
| 
								 | 
							
								  var aPointer = i,
							 | 
						||
| 
								 | 
							
								      aLength = a.length,
							 | 
						||
| 
								 | 
							
								      bPointer = 0,
							 | 
						||
| 
								 | 
							
								      bLength = b.length,
							 | 
						||
| 
								 | 
							
								      aHead,
							 | 
						||
| 
								 | 
							
								      bHead;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while (aPointer < aLength && bPointer < bLength) {
							 | 
						||
| 
								 | 
							
								    aHead = a[aPointer];
							 | 
						||
| 
								 | 
							
								    bHead = b[bPointer];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (aHead <= bHead) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (array.length === 0 || array[array.length - 1] !== aHead)
							 | 
						||
| 
								 | 
							
								        array.push(aHead);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      aPointer++;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								      if (array.length === 0 || array[array.length - 1] !== bHead)
							 | 
						||
| 
								 | 
							
								        array.push(bHead);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      bPointer++;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Filling
							 | 
						||
| 
								 | 
							
								  // TODO: it's possible to optimize a bit here, since the condition is only
							 | 
						||
| 
								 | 
							
								  // relevant the first time
							 | 
						||
| 
								 | 
							
								  while (aPointer < aLength) {
							 | 
						||
| 
								 | 
							
								    aHead = a[aPointer++];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (array.length === 0 || array[array.length - 1] !== aHead)
							 | 
						||
| 
								 | 
							
								      array.push(aHead);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  while (bPointer < bLength) {
							 | 
						||
| 
								 | 
							
								    bHead = b[bPointer++];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (array.length === 0 || array[array.length - 1] !== bHead)
							 | 
						||
| 
								 | 
							
								      array.push(bHead);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return array;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Perform the intersection of two already unique sorted array-like structures into one.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {array} a - First array.
							 | 
						||
| 
								 | 
							
								 * @param  {array} b - Second array.
							 | 
						||
| 
								 | 
							
								 * @return {array}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								exports.intersectionUniqueArrays = function(a, b) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // One of the arrays is empty
							 | 
						||
| 
								 | 
							
								  if (a.length === 0 || b.length === 0)
							 | 
						||
| 
								 | 
							
								    return new a.constructor(0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Finding min array
							 | 
						||
| 
								 | 
							
								  var tmp;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (a[0] > b[0]) {
							 | 
						||
| 
								 | 
							
								    tmp = a;
							 | 
						||
| 
								 | 
							
								    a = b;
							 | 
						||
| 
								 | 
							
								    b = tmp;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // If array have non overlapping ranges, there is no intersection
							 | 
						||
| 
								 | 
							
								  var aEnd = a[a.length - 1],
							 | 
						||
| 
								 | 
							
								      bStart = b[0];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (aEnd < bStart)
							 | 
						||
| 
								 | 
							
								    return new a.constructor(0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Initializing target
							 | 
						||
| 
								 | 
							
								  var array = new a.constructor();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Handling overlap
							 | 
						||
| 
								 | 
							
								  var aPointer = binarySearch.lowerBound(a, bStart),
							 | 
						||
| 
								 | 
							
								      aLength = a.length,
							 | 
						||
| 
								 | 
							
								      bPointer = 0,
							 | 
						||
| 
								 | 
							
								      bLength = binarySearch.upperBound(b, aEnd),
							 | 
						||
| 
								 | 
							
								      aHead,
							 | 
						||
| 
								 | 
							
								      bHead;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while (aPointer < aLength && bPointer < bLength) {
							 | 
						||
| 
								 | 
							
								    aHead = a[aPointer];
							 | 
						||
| 
								 | 
							
								    bHead = b[bPointer];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (aHead < bHead) {
							 | 
						||
| 
								 | 
							
								      aPointer = binarySearch.lowerBound(a, bHead, aPointer + 1);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else if (aHead > bHead) {
							 | 
						||
| 
								 | 
							
								      bPointer = binarySearch.lowerBound(b, aHead, bPointer + 1);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								      array.push(aHead);
							 | 
						||
| 
								 | 
							
								      aPointer++;
							 | 
						||
| 
								 | 
							
								      bPointer++;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return array;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Merge k sorted array-like structures into one.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {array<array>} arrays - Arrays to merge.
							 | 
						||
| 
								 | 
							
								 * @return {array}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function kWayMergeArrays(arrays) {
							 | 
						||
| 
								 | 
							
								  var length = 0,
							 | 
						||
| 
								 | 
							
								      max = -Infinity,
							 | 
						||
| 
								 | 
							
								      al,
							 | 
						||
| 
								 | 
							
								      i,
							 | 
						||
| 
								 | 
							
								      l;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var filtered = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (i = 0, l = arrays.length; i < l; i++) {
							 | 
						||
| 
								 | 
							
								    al = arrays[i].length;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (al === 0)
							 | 
						||
| 
								 | 
							
								      continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    filtered.push(arrays[i]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    length += al;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (al > max)
							 | 
						||
| 
								 | 
							
								      max = al;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (filtered.length === 0)
							 | 
						||
| 
								 | 
							
								    return new arrays[0].constructor(0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (filtered.length === 1)
							 | 
						||
| 
								 | 
							
								    return filtered[0].slice();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (filtered.length === 2)
							 | 
						||
| 
								 | 
							
								    return mergeArrays(filtered[0], filtered[1]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  arrays = filtered;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var array = new arrays[0].constructor(length);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var PointerArray = typed.getPointerArray(max);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var pointers = new PointerArray(arrays.length);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // TODO: benchmark vs. a binomial heap
							 | 
						||
| 
								 | 
							
								  var heap = new FibonacciHeap(function(a, b) {
							 | 
						||
| 
								 | 
							
								    a = arrays[a][pointers[a]];
							 | 
						||
| 
								 | 
							
								    b = arrays[b][pointers[b]];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (a < b)
							 | 
						||
| 
								 | 
							
								      return -1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (a > b)
							 | 
						||
| 
								 | 
							
								      return 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (i = 0; i < l; i++)
							 | 
						||
| 
								 | 
							
								    heap.push(i);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  i = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var p,
							 | 
						||
| 
								 | 
							
								      v;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while (heap.size) {
							 | 
						||
| 
								 | 
							
								    p = heap.pop();
							 | 
						||
| 
								 | 
							
								    v = arrays[p][pointers[p]++];
							 | 
						||
| 
								 | 
							
								    array[i++] = v;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (pointers[p] < arrays[p].length)
							 | 
						||
| 
								 | 
							
								      heap.push(p);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return array;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Perform the union of k sorted unique array-like structures into one.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {array<array>} arrays - Arrays to merge.
							 | 
						||
| 
								 | 
							
								 * @return {array}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function kWayUnionUniqueArrays(arrays) {
							 | 
						||
| 
								 | 
							
								  var max = -Infinity,
							 | 
						||
| 
								 | 
							
								      al,
							 | 
						||
| 
								 | 
							
								      i,
							 | 
						||
| 
								 | 
							
								      l;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var filtered = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (i = 0, l = arrays.length; i < l; i++) {
							 | 
						||
| 
								 | 
							
								    al = arrays[i].length;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (al === 0)
							 | 
						||
| 
								 | 
							
								      continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    filtered.push(arrays[i]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (al > max)
							 | 
						||
| 
								 | 
							
								      max = al;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (filtered.length === 0)
							 | 
						||
| 
								 | 
							
								    return new arrays[0].constructor(0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (filtered.length === 1)
							 | 
						||
| 
								 | 
							
								    return filtered[0].slice();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (filtered.length === 2)
							 | 
						||
| 
								 | 
							
								    return unionUniqueArrays(filtered[0], filtered[1]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  arrays = filtered;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var array = new arrays[0].constructor();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var PointerArray = typed.getPointerArray(max);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var pointers = new PointerArray(arrays.length);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // TODO: benchmark vs. a binomial heap
							 | 
						||
| 
								 | 
							
								  var heap = new FibonacciHeap(function(a, b) {
							 | 
						||
| 
								 | 
							
								    a = arrays[a][pointers[a]];
							 | 
						||
| 
								 | 
							
								    b = arrays[b][pointers[b]];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (a < b)
							 | 
						||
| 
								 | 
							
								      return -1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (a > b)
							 | 
						||
| 
								 | 
							
								      return 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (i = 0; i < l; i++)
							 | 
						||
| 
								 | 
							
								    heap.push(i);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var p,
							 | 
						||
| 
								 | 
							
								      v;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while (heap.size) {
							 | 
						||
| 
								 | 
							
								    p = heap.pop();
							 | 
						||
| 
								 | 
							
								    v = arrays[p][pointers[p]++];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (array.length === 0 || array[array.length - 1] !== v)
							 | 
						||
| 
								 | 
							
								      array.push(v);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (pointers[p] < arrays[p].length)
							 | 
						||
| 
								 | 
							
								      heap.push(p);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return array;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Perform the intersection of k sorted array-like structures into one.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {array<array>} arrays - Arrays to merge.
							 | 
						||
| 
								 | 
							
								 * @return {array}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								exports.kWayIntersectionUniqueArrays = function(arrays) {
							 | 
						||
| 
								 | 
							
								  var max = -Infinity,
							 | 
						||
| 
								 | 
							
								      maxStart = -Infinity,
							 | 
						||
| 
								 | 
							
								      minEnd = Infinity,
							 | 
						||
| 
								 | 
							
								      first,
							 | 
						||
| 
								 | 
							
								      last,
							 | 
						||
| 
								 | 
							
								      al,
							 | 
						||
| 
								 | 
							
								      i,
							 | 
						||
| 
								 | 
							
								      l;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (i = 0, l = arrays.length; i < l; i++) {
							 | 
						||
| 
								 | 
							
								    al = arrays[i].length;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // If one of the arrays is empty, so is the intersection
							 | 
						||
| 
								 | 
							
								    if (al === 0)
							 | 
						||
| 
								 | 
							
								      return [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (al > max)
							 | 
						||
| 
								 | 
							
								      max = al;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    first = arrays[i][0];
							 | 
						||
| 
								 | 
							
								    last = arrays[i][al - 1];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (first > maxStart)
							 | 
						||
| 
								 | 
							
								      maxStart = first;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (last < minEnd)
							 | 
						||
| 
								 | 
							
								      minEnd = last;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Full overlap is impossible
							 | 
						||
| 
								 | 
							
								  if (maxStart > minEnd)
							 | 
						||
| 
								 | 
							
								    return [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Only one value
							 | 
						||
| 
								 | 
							
								  if (maxStart === minEnd)
							 | 
						||
| 
								 | 
							
								    return [maxStart];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // NOTE: trying to outsmart I(D,I(C,I(A,B))) is pointless unfortunately...
							 | 
						||
| 
								 | 
							
								  // NOTE: I tried to be very clever about bounds but it does not seem
							 | 
						||
| 
								 | 
							
								  // to improve the performance of the algorithm.
							 | 
						||
| 
								 | 
							
								  var a, b,
							 | 
						||
| 
								 | 
							
								      array = arrays[0],
							 | 
						||
| 
								 | 
							
								      aPointer,
							 | 
						||
| 
								 | 
							
								      bPointer,
							 | 
						||
| 
								 | 
							
								      aLimit,
							 | 
						||
| 
								 | 
							
								      bLimit,
							 | 
						||
| 
								 | 
							
								      aHead,
							 | 
						||
| 
								 | 
							
								      bHead,
							 | 
						||
| 
								 | 
							
								      start = maxStart;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (i = 1; i < l; i++) {
							 | 
						||
| 
								 | 
							
								    a = array;
							 | 
						||
| 
								 | 
							
								    b = arrays[i];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Change that to `[]` and observe some perf drops on V8...
							 | 
						||
| 
								 | 
							
								    array = new Array();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    aPointer = 0;
							 | 
						||
| 
								 | 
							
								    bPointer = binarySearch.lowerBound(b, start);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    aLimit = a.length;
							 | 
						||
| 
								 | 
							
								    bLimit = b.length;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    while (aPointer < aLimit && bPointer < bLimit) {
							 | 
						||
| 
								 | 
							
								      aHead = a[aPointer];
							 | 
						||
| 
								 | 
							
								      bHead = b[bPointer];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (aHead < bHead) {
							 | 
						||
| 
								 | 
							
								        aPointer = binarySearch.lowerBound(a, bHead, aPointer + 1);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      else if (aHead > bHead) {
							 | 
						||
| 
								 | 
							
								        bPointer = binarySearch.lowerBound(b, aHead, bPointer + 1);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      else {
							 | 
						||
| 
								 | 
							
								        array.push(aHead);
							 | 
						||
| 
								 | 
							
								        aPointer++;
							 | 
						||
| 
								 | 
							
								        bPointer++;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (array.length === 0)
							 | 
						||
| 
								 | 
							
								      return array;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    start = array[0];
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return array;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Variadic merging all of the given arrays.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {...array}
							 | 
						||
| 
								 | 
							
								 * @return {array}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								exports.merge = function() {
							 | 
						||
| 
								 | 
							
								  if (arguments.length === 2) {
							 | 
						||
| 
								 | 
							
								    if (isArrayLike(arguments[0]))
							 | 
						||
| 
								 | 
							
								      return mergeArrays(arguments[0], arguments[1]);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  else {
							 | 
						||
| 
								 | 
							
								    if (isArrayLike(arguments[0]))
							 | 
						||
| 
								 | 
							
								      return kWayMergeArrays(arguments);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return null;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Variadic function performing the union of all the given unique arrays.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {...array}
							 | 
						||
| 
								 | 
							
								 * @return {array}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								exports.unionUnique = function() {
							 | 
						||
| 
								 | 
							
								  if (arguments.length === 2) {
							 | 
						||
| 
								 | 
							
								    if (isArrayLike(arguments[0]))
							 | 
						||
| 
								 | 
							
								      return unionUniqueArrays(arguments[0], arguments[1]);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  else {
							 | 
						||
| 
								 | 
							
								    if (isArrayLike(arguments[0]))
							 | 
						||
| 
								 | 
							
								      return kWayUnionUniqueArrays(arguments);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return null;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Variadic function performing the intersection of all the given unique arrays.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {...array}
							 | 
						||
| 
								 | 
							
								 * @return {array}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								exports.intersectionUnique = function() {
							 | 
						||
| 
								 | 
							
								  if (arguments.length === 2) {
							 | 
						||
| 
								 | 
							
								    if (isArrayLike(arguments[0]))
							 | 
						||
| 
								 | 
							
								      return exports.intersectionUniqueArrays(arguments[0], arguments[1]);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  else {
							 | 
						||
| 
								 | 
							
								    if (isArrayLike(arguments[0]))
							 | 
						||
| 
								 | 
							
								      return exports.kWayIntersectionUniqueArrays(arguments);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return null;
							 | 
						||
| 
								 | 
							
								};
							 |