import {ArrayList, ArraySet, Comparator, NestedArray} from './type'; import {includedInBy} from './comparator'; import {uncurry2} from './core'; import {isNot} from './predicate'; // ------------ @author Daniel de Oliveira ----------------- export const intersectionBy = (compare?: Comparator) => (aas: NestedArray): ArraySet => { if (aas.length < 1) return []; if (aas.length === 1) return aas[0]; if (compare) return aas.reduce(uncurry2(_intersectBy(compare))); for (let i = 0; i < aas.length - 1; i++) { // see https://stackoverflow.com/questions/1885557/simplest-code-for-array-intersection-in-javascript, answer of le_m aas[i+1] = aas[i].filter(Set.prototype.has, new Set(aas[i + 1])); } return uniqueBy(undefined as any)(aas[aas.length - 1]); }; export const unionBy = (compare?: Comparator) => (aas: NestedArray): ArraySet => { if (aas.length < 1) return []; if (compare) return aas.reduce( (acc: any, val:any) => val ? _uniteBy(compare)(acc)(val) : acc); // https://stackoverflow.com/questions/10865025/merge-flatten-an-array-of-arrays, answer of Gumbo and Mark Amery return uniqueBy(undefined as any)([].concat.apply([], aas)); }; export const intersectBy = (compare?: Comparator) => (as1: Array) => (as2: ArrayList): ArraySet => intersectionBy(compare)([as1, as2]); export const uniteBy = (compare?: Comparator) => (as1: Array) => (as2: Array): ArraySet => unionBy(compare)([as1, as2]); // Generate a new list with elements which are contained in as but not in subtrahend export const subtractBy = (compare?: Comparator) => (subtrahend: Array) => (as: ArrayList): ArraySet => { const filterFun = compare ? isNot(includedInBy(compare)(subtrahend)) : (() => { const unionSubtrahendsSet = new Set(subtrahend); return (x: A) => !unionSubtrahendsSet.has(x); })(); return uniqueBy(undefined as any)(as).filter(filterFun); }; export const uniqueBy = (compare?: Comparator) => (as: ArrayList): ArraySet => { return compare ? as.reduce((acc: Array, val) => includedInBy(compare)(acc)(val) ? acc : acc.concat([val]) ,[]) : Array.from(new Set(as)); }; // @returns the union of a1 and a2 const _uniteBy = (compare: Comparator) => (as1: Array) => (as2: Array) => as1.concat( as2.filter(isNot(includedInBy(compare)(as1)))); const _intersectBy = (compare: Comparator) => (as1: Array) => (as2: Array) => as1.filter(includedInBy(compare)(as2)); export const intersection = intersectionBy(); export const union = unionBy(); export const intersect = intersectBy(); export const unite = uniteBy(); // Generate a new list with elements which are contained in as but not in subtrahend export const subtract = subtractBy(); export const unique = uniqueBy();