UNPKG

@beenotung/tslib

Version:
671 lines (670 loc) 15.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.z_score = exports.mean = exports.range = exports.defaultComparator = void 0; exports.clearArray = clearArray; exports.replaceArray = replaceArray; exports.unique = unique; exports.rightMost = rightMost; exports.leftMost = leftMost; exports.popN = popN; exports.popUntilN = popUntilN; exports.shiftN = shiftN; exports.shiftUntilN = shiftUntilN; exports.last = last; exports.maybeLast = maybeLast; exports.fromFileList = fromFileList; exports.array_contains = array_contains; exports.insert = insert; exports.insert_sorted = insert_sorted; exports.cloneArray = cloneArray; exports.sort = sort; exports.removeByIdx = removeByIdx; exports.remove = remove; exports.removeBy = removeBy; exports.nodup = nodup; exports.removeDup = removeDup; exports.insertNoDup = insertNoDup; exports.insertNoDupWithKey = insertNoDupWithKey; exports.removeDupByKey = removeDupByKey; exports.removeByKey = removeByKey; exports.arrayFromRange = arrayFromRange; exports.repeat = repeat; exports.filterByKey = filterByKey; exports.toArray = toArray; exports.flatten = flatten; exports.push = push; exports.binArray = binArray; exports.binArrayBy = binArrayBy; exports.partitionArrayBy = partitionArrayBy; exports.zipArray = zipArray; exports.countArray = countArray; exports.asyncCountArray = asyncCountArray; exports.max = max; exports.min = min; exports.sum = sum; exports.average = average; exports.standard_deviation = standard_deviation; exports.standard_score = standard_score; exports.sumByFunc = sumByFunc; exports.maxByFunc = maxByFunc; exports.minByFunc = minByFunc; exports.maxByField = maxByField; exports.minByField = minByField; exports.sumByField = sumByField; exports.median = median; exports.countElement = countElement; exports.countAll = countAll; exports.mode = mode; exports.shuffle = shuffle; exports.shuffledBinArray = shuffledBinArray; exports.shuffledIndices = shuffledIndices; exports.genCombination = genCombination; exports.flattenAll = flattenAll; exports.getMaxArraySize = getMaxArraySize; exports.pushForward = pushForward; exports.pushBackward = pushBackward; exports.makeArray = makeArray; exports.arrayToObject = arrayToObject; const compare_1 = require("./compare"); const lang_1 = require("./lang"); const map_1 = require("./map"); const maybe_1 = require("./maybe"); const random_1 = require("./random"); const string_1 = require("./string"); /** * inplace delete all element from the array * @return old elements * */ function clearArray(xs) { return xs.splice(0, xs.length); } /** * inplace replace all element in the array * @return the old elements * */ function replaceArray(dest, src) { clearArray(dest); dest.push(...src); return dest; } /** * only use `===` to compare * @warning slow * @return new array * */ function unique(xs) { return Array.from(new Set(xs)); } function rightMost(n, xs) { return xs.slice(xs.length - n, xs.length); } function leftMost(n, xs) { return xs.slice(0, n); } /** inplace update */ function popN(n, xs) { (0, lang_1.forI)(_ => xs.pop(), n); } /** inplace update */ function popUntilN(n, xs) { (0, lang_1.forI)(_ => xs.pop(), xs.length - n); } /** inplace update */ function shiftN(n, xs) { (0, lang_1.forI)(_ => xs.shift(), n); } /** inplace update */ function shiftUntilN(n, xs) { (0, lang_1.forI)(_ => xs.shift(), xs.length - n); } function last(xs, skipCheck = false) { if (!skipCheck && xs.length === 0) { throw new TypeError('xs is not non-empty array'); } return xs[xs.length - 1]; } function maybeLast(xs) { return maybe_1.Maybe.fromNullable(xs[xs.length - 1]); } function fromFileList(files) { return (0, lang_1.mapI)(i => files.item(i), files.length); } function array_contains(xs, x) { return xs.indexOf(x) !== -1; } function insert(xs, index, x) { xs.splice(index, 0, x); } /** * insert into Ascending sorted array * */ function insert_sorted(xs, comparator, x, order = 'ascending') { const target = order === 'ascending' ? compare_1.CompareResult.Larger : compare_1.CompareResult.Smaller; for (let i = 0; i < xs.length; i++) { if (comparator(xs[i], x) === target) { insert(xs, i, x); return; } } xs.push(x); } const defaultComparator = (a, b) => { if (typeof a === 'string' && typeof b === 'string') { return (0, string_1.compare_string)(a, b); } return (0, compare_1.compare)(a, b); }; exports.defaultComparator = defaultComparator; /** * * wrapper of slice, because it's confusing between slice and splice * * performance reference: https://jsperf.com/array-clone * */ function cloneArray(xs) { return xs.slice(); } /** * @return in-place sorted, original array * */ function sort(xs, comparator = exports.defaultComparator) { return xs.sort(comparator); } /** * @remark inplace update * @return original array * */ function removeByIdx(xs, i) { xs.splice(i, 1); return xs; } /** * @remark inplace update * @return original array * */ function remove(xs, x) { const idx = xs.indexOf(x); if (idx !== -1) { xs.splice(idx, 1); } } /** * @remark inplace update * @return original array * */ function removeBy(xs, f) { for (let i = 0; i < xs.length; i++) { if (f(xs[i])) { xs.splice(i, 1); return xs; } } return xs; } function nodup(xs) { const s = new Set(); xs.forEach(x => s.add(x)); return Array.from(s.values()); } /** * inplace delete all duplicated element from the array (only one copy is kept) * @return old array * */ function removeDup(xs) { const ys = nodup(xs); clearArray(xs); xs.push(...ys); return xs; } /** * inplace insert elements into the array * @return old array * */ function insertNoDup(acc, newXs) { acc.push(...newXs); return removeDup(acc); } /** * inplace insert elements into the array * @return old array * */ function insertNoDupWithKey(acc, newXs, key) { newXs.forEach(newX => { if (!acc.find(x => x[key] === newX[key])) { acc.push(newX); } }); return acc; } /** * inplace operation * @return old array * */ function removeDupByKey(xs, key) { const t = {}; xs.map(x => (t[x[key]] = x)); replaceArray(xs, (0, lang_1.objValues)(t)); return xs; } /** * inplace update * @return old array * */ function removeByKey(xs, key, keys) { return replaceArray(xs, xs.filter(x => !array_contains(keys, x[key]))); } /** * including end * */ function arrayFromRange(start, end, step = 1) { const res = []; for (let i = start; i <= end; i += step) { res.push(i); } return res; } /** @deprecated renamed to arrayFromRange */ exports.range = arrayFromRange; function repeat(x, n) { const xs = new Array(n); xs.fill(x); return xs; } function filterByKey(src, key, keys) { return src.filter(x => keys.indexOf(x[key]) !== -1); } /** @deprecated use Array.from(xs) instead */ function toArray(xs) { // return mapI(i => xs[i], xs.length); return Array.prototype.concat.apply([], xs); } function flatten(xss) { return [].concat(...xss); } /** * array.push is not monadic, this is a wrapper to make it monadic * */ function push(res, ...xs) { res.push(...xs); return res; } function binArray(xs, binSize) { const res = []; let acc = []; for (const x of xs) { if (acc.length >= binSize) { res.push(acc); acc = []; } acc.push(x); } if (acc.length !== 0) { res.push(acc); } return res; } /** * non-curry version of `groupBy` in functional.ts * */ function binArrayBy(xs, mapper) { const res = new Map(); for (const x of xs) { const k = mapper(x); const xs = res.get(k); if (xs) { xs.push(x); } else { res.set(k, [x]); } } return res; } function partitionArrayBy(xs, f) { const true_xs = []; const false_xs = []; for (const x of xs) { if (f(x)) { true_xs.push(x); } else { false_xs.push(x); } } return [true_xs, false_xs]; } function zipArray(a, b) { const res = new Array(Math.min(a.length, b.length)); for (let i = 0; i < res.length; i++) { res[i] = [a[i], b[i]]; } return res; } function countArray(xs, f) { let acc = 0; const n = xs.length; for (let i = 0; i < n; i++) { if (f(xs[i], i, xs)) { acc++; } } return acc; } function asyncCountArray(xs, f) { let acc = 0; return Promise.all(xs.map((x, i, xs) => f(x, i, xs).then(b => (acc += b ? 1 : 0)))).then(() => acc); } function max(xs) { const n = xs.length; let acc = xs[0]; for (let i = 1; i < n; i++) { const c = xs[i]; if (acc < c) { acc = c; } } return acc; } function min(xs) { const n = xs.length; let acc = xs[0]; for (let i = 1; i < n; i++) { const c = xs[i]; if (acc > c) { acc = c; } } return acc; } function sum(xs) { let acc = 0; const n = xs.length; for (let i = 0; i < n; i++) { acc += xs[i]; } return acc; } function average(xs) { return sum(xs) / xs.length; } exports.mean = average; function standard_deviation(xs, mode = 'sample', mean = average(xs)) { let acc = 0; const n = xs.length; for (let i = 0; i < n; i++) { const diff = xs[i] - mean; acc += diff * diff; } if (mode === 'sample') { acc /= n - 1; } else { acc /= n; } return Math.sqrt(acc); } function standard_score(xs, mode = 'sample') { const n = xs.length; const result = new Array(n); const mean = average(xs); const sd = standard_deviation(xs, mode, mean); for (let i = 0; i < n; i++) { result[i] = (xs[i] - mean) / sd; } return result; } exports.z_score = standard_score; function sumByFunc(xs, mapper) { let acc = 0; const n = xs.length; for (let i = 0; i < n; i++) { acc += mapper(xs[i]); } return acc; } function maxByFunc(xs, comparator) { let acc = xs[0]; const n = xs.length; for (let i = 1; i < n; i++) { const c = xs[i]; if (comparator(acc, c) < 0) { acc = c; } } return acc; } function minByFunc(xs, comparator) { let acc = xs[0]; const n = xs.length; for (let i = 1; i < n; i++) { const c = xs[i]; if (comparator(acc, c) > 0) { acc = c; } } return acc; } function maxByField(xs, key) { let acc = xs[0]; const n = xs.length; for (let i = 1; i < n; i++) { const c = xs[i]; if ((0, exports.defaultComparator)(acc[key], c[key]) < 0) { acc = c; } } return acc; } function minByField(xs, key) { let acc = xs[0]; const n = xs.length; for (let i = 1; i < n; i++) { const c = xs[i]; if ((0, exports.defaultComparator)(acc[key], c[key]) > 0) { acc = c; } } return acc; } function sumByField(xs, key) { let acc = 0; const n = xs.length; for (let i = 0; i < n; i++) { acc += xs[i][key]; } return acc; } /** * side-effect: the array will be sorted in-place if instructed * * default will sort the array * */ function median(xs, options) { if (xs.length === 0) { return undefined; } if (xs.length === 1) { return xs[0]; } if (!options || options.sort !== false) { xs.sort(options && typeof options.sort === 'function' ? options.sort : exports.defaultComparator); } const n = xs.length; if (n % 2) { /* odd number */ return xs[(n - 1) / 2]; } /* even number */ const m = n / 2; const a = xs[m - 1]; const b = xs[m]; if (typeof a === 'number' && typeof b === 'number') { return ((a + b) / 2.0); } if (options && options.merger) { return options.merger(a, b); } throw new Error('cannot find median of even array'); } function countElement(xs, x) { let acc = 0; const n = xs.length; for (let i = 1; i < n; i++) { if (xs[i] === x) { acc++; } } return acc; } function countAll(xs) { const counts = new Map(); xs.forEach(x => (0, map_1.incMap)(counts, x)); return counts; } function mode(xs) { const counts = Array.from(countAll(xs).entries()); if (counts.length === 0) { return undefined; } const maxCount = maxByField(counts, 1); return maxCount ? maxCount[0] : undefined; } function shuffle(xs, n = xs.length) { xs = xs.slice(); for (let i = 0; i < n; i++) { const a = i; const b = random_1.Random.nextInt(n); const t = xs[a]; xs[a] = xs[b]; xs[b] = t; } return xs; } function shuffledBinArray(xs, binSize, nSwap) { return binArray(shuffle(xs, nSwap), binSize); } function shuffledIndices(n) { return shuffle((0, exports.range)(0, n - 1)); } /** * TODO assign a better name * e.g. f [a,b,c] 1 ~~> [[a],[b],[c]] * e.g. f [a,b,c] 2 ~~> [ [a,a],[a,b],[a,c], * [b,a],[b,b],[b,c], * [c,a],[c,b],[c,c] ] * */ function genCombination(cs, size) { if (size < 1) { return []; } let xss = cs.map(c => [c]); let i = 1; for (;;) { if (i === size) { return xss; } i++; const acc = []; const n = xss.length; for (let x = 0; x < n; x++) { const n = cs.length; for (let c = 0; c < n; c++) { const xs = xss[x].slice(); xs.push(cs[c]); acc.push(xs); } } xss = acc; } } function flattenAll(xs) { const ys = []; flattenIoList(xs, ys); return ys; } function flattenIoList(xs, ys) { const n = xs.length; for (let i = 0; i < n; i++) { const x = xs[i]; if (Array.isArray(x)) { flattenIoList(x, ys); } else { ys.push(x); } } } function _getMaxArraySize() { let i = 1; try { for (;;) { new Array(i); i += i; } } catch (e) { let min = i / 2; let max = i; for (; min + 1 < max;) { const m = Math.round((min + max) / 2); try { new Array(m); min = m; } catch (e) { max = m; } } return min; } } let MaxArraySize; function getMaxArraySize() { if (!MaxArraySize) { MaxArraySize = _getMaxArraySize(); } return MaxArraySize; } function pushForward(xs, x) { const idx = xs.indexOf(x); if (idx === -1) { xs.unshift(x); return; } if (idx === 0) { return; // already at head } const t = xs[idx - 1]; xs[idx - 1] = x; xs[idx] = t; } function pushBackward(xs, x) { const idx = xs.indexOf(x); if (idx === -1) { xs.push(x); return; } if (idx === xs.length - 1) { return; // already at tail } const t = xs[idx + 1]; xs[idx + 1] = x; xs[idx] = t; } function makeArray(n, f) { const res = new Array(n); for (let i = 0; i < n; i++) { res[i] = f(i); } return res; } function arrayToObject(xs, keyFn) { const o = {}; xs.forEach((x, i, xs) => { const key = keyFn(x, i, xs); o[key] = x; }); return o; }