/** * Count the number of elements that satisfy the predicate */ export function countIf(f, xs) { return xs.filter(f).length; } /** * Count the number of elements that is equal to the element */ export function count(a, xs) { return countIf((x)=>x === a, xs); } /** * Concatenate an array of arrays */ export function concat(xss) { return [].concat(...xss); } /** * Intersperse the element between the elements of the array * @param sep The element to be interspersed */ export function intersperse(sep, xs) { return concat(xs.map((x)=>[ sep, x ])).slice(1); } /** * Returns the array of elements that is not equal to the element */ export function erase(a, xs) { return xs.filter((x)=>x !== a); } /** * Finds the array of all elements in the first array not contained in the second array. * The order of result values are determined by the first array. */ export function difference(xs, ys) { return xs.filter((x)=>!ys.includes(x)); } /** * Remove all but the first element from every group of equivalent elements */ export function unique(xs) { return [ ...new Set(xs) ]; } export function uniqBy(a, key) { const seen = new Set(); return a.filter(function(item) { const k = key(item); return seen.has(k) ? false : seen.add(k); }); } export function sum(xs) { return xs.reduce((a, b)=>a + b, 0); } export function maximum(xs) { return Math.max(...xs); } /** * Splits an array based on the equivalence relation. * The concatenation of the result is equal to the argument. */ export function groupBy(f, xs) { const groups = []; for (const x of xs){ if (groups.length !== 0 && f(groups[groups.length - 1][0], x)) { groups[groups.length - 1].push(x); } else { groups.push([ x ]); } } return groups; } /** * Splits an array based on the equivalence relation induced by the function. * The concatenation of the result is equal to the argument. */ export function groupOn(f, xs) { return groupBy((a, b)=>f(a) === f(b), xs); } export function groupByX(collections, keySelector) { return collections.reduce((obj, item)=>{ const key = keySelector(item); if (!Object.prototype.hasOwnProperty.call(obj, key)) { obj[key] = []; } obj[key].push(item); return obj; }, {}); } /** * Compare two arrays by lexicographical order */ export function lessThan(xs, ys) { for(let i = 0; i < Math.min(xs.length, ys.length); i++){ if (xs[i] < ys[i]) return true; if (xs[i] > ys[i]) return false; } return xs.length < ys.length; } /** * Returns the longest prefix of elements that satisfy the predicate */ export function takeWhile(f, xs) { const ys = []; for (const x of xs){ if (f(x)) { ys.push(x); } else { break; } } return ys; } export function cumulativeSum(xs) { const ys = Array.from(xs); // deep copy for(let i = 1; i < ys.length; i++)ys[i] += ys[i - 1]; return ys; } export function toArray(x) { return Array.isArray(x) ? x : x != null ? [ x ] : []; } export function toSingle(x) { return Array.isArray(x) ? x[0] : x; } export function toSingleLast(x) { return Array.isArray(x) ? x.at(-1) : x; }