export function countIf(f: (x: T) => boolean, xs: T[]): number { return xs.filter(f).length; } export function count(x: T, xs: T[]): number { return countIf(y => x === y, xs); } export function concat(xss: T[][]): T[] { return ([] as T[]).concat(...xss); } export function intersperse(sep: T, xs: T[]): T[] { return concat(xs.map(x => [sep, x])).slice(1); } export function erase(x: T, xs: T[]): T[] { return xs.filter(y => x !== y); } /** * 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(includes: T[], excludes: T[]): T[] { return includes.filter(x => !excludes.includes(x)); } export function unique(xs: T[]): T[] { return [...new Set(xs)]; } export function sum(xs: number[]): number { return xs.reduce((a, b) => a + b, 0); } export function groupBy(f: (x: T, y: T) => boolean, xs: T[]): T[][] { const groups = [] as T[][]; 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; } export function groupOn(f: (x: T) => S, xs: T[]): T[][] { return groupBy((a, b) => f(a) === f(b), xs); } export function lessThan(xs: number[], ys: number[]): boolean { 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; } export function takeWhile(f: (x: T) => boolean, xs: T[]): T[] { const ys = []; for (const x of xs) { if (f(x)) { ys.push(x); } else { break; } } return ys; }