/**
* @module set_utils
* @description A set of utilities for performing set operations on arrays (as if they were sets).
* All the methods will also take sets.
*/
// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
// These versions can also take arrays will return the same type as they are given (sets or
// arrays).
const slice = Array.prototype.slice;
const filter = Array.prototype.filter;
export function toSet(value) {
return value instanceof Set ? [true, value] : [false, new Set(value)];
}
export function isSuperset(a, b) {
let [, set] = toSet(a);
let [, subset] = toSet(b);
for (var elem of subset) {
if (!set.has(elem)) {
return false;
}
}
return true;
}
export function union(a, b) {
let [isSet, setA] = toSet(a);
let [, setB] = toSet(b);
const union = new Set(setA);
for (var elem of setB) {
union.add(elem);
}
return isSet ? union : Array.from(union);
}
// Find the member in a full set that is in the tags (where typeOf prefix is
// not available to find this via Model#typeOf)
export function member(tags, fullSet) {
let set = intersection(tags, fullSet);
if (set.size > 1) {
throw Error(`Not one value of {${fullSet}} in {${Array.from(tags)}}`);
} else if (set.size === 0) {
return null;
}
return Array.from(set)[0];
}
export function intersection(a, b) {
let [isSet, setA] = toSet(a);
let [, setB] = toSet(b);
const intersection = new Set();
for (var elem of setB) {
if (setA.has(elem)) {
intersection.add(elem);
}
}
return isSet ? intersection : Array.from(intersection);
}
export function symmetricDifference(a, b) {
let [isSet, setA] = toSet(a);
let [, setB] = toSet(b);
var difference = new Set(setA);
for (var elem of setB) {
if (difference.has(elem)) {
difference.delete(elem);
} else {
difference.add(elem);
}
}
return isSet ? difference : Array.from(difference);
}
export function difference(a, b) {
let [isSet, setA] = toSet(a);
let [, setB] = toSet(b);
var difference = new Set(setA);
for (var elem of setB) {
difference.delete(elem);
}
return isSet ? difference : Array.from(difference);
}
/**
* Returns an array with only the unique values in the source array.
*
* @param {Array|Set} input an array (a set is OK but this method won't do anything)
* @returns {Array|Set} an array or set with unique values only (matching the type of the argument).
*/
export function unique(array) {
let [isSet, set] = toSet(array);
return isSet ? array : Array.from(set);
}
// wtf does this actually do
export function without(array) {
let [isSet, set] = toSet(array);
for (var i = 1; i < arguments.length; i++) {
set.delete(arguments[i]);
}
return isSet ? set : Array.from(set);
}