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();