@beenotung/tslib
Version:
utils library in Typescript
667 lines • 17.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.pushBackward = exports.pushForward = exports.getMaxArraySize = exports.flattenAll = exports.genCombination = exports.shuffledIndecies = exports.shuffledIndices = exports.shuffledBinArray = exports.shuffle = exports.mode = exports.countAll = exports.countElement = exports.median = exports.sumByField = exports.minByField = exports.maxByField = exports.minByFunc = exports.maxByFunc = exports.sumByFunc = exports.sum = exports.min = exports.max = exports.asyncCountArray = exports.countArray = exports.mapArray = exports.zipArray = exports.partitionArrayBy = exports.binArrayBy = exports.binArray = exports.push = exports.flatten = exports.toArray = exports.filterByKey = exports.repeat = exports.range = exports.removeByKey = exports.removeDupByKey = exports.insertNoDupWithKey = exports.insertNoDup = exports.removeDup = exports.nodup = exports.removeBy = exports.remove = exports.removeByIdx = exports.sort = exports.sortBy = exports.insertSortBy = exports.cloneArray = exports.defaultComparator = exports.insert_sorted = exports.insert = exports.array_contains = exports.fromFileList = exports.maybeLast = exports.last = exports.shiftUntilN = exports.shiftN = exports.popUntilN = exports.popN = exports.leftMost = exports.rightMost = exports.unique = exports.includes = exports.takeAll = exports.replaceArray = exports.clear = exports.clearArray = void 0;
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);
}
exports.clearArray = clearArray;
/** @deprecated renamed to clearArray */
exports.clear = clearArray;
/**
* inplace replace all element in the array
* @return the old elements
* */
function replaceArray(dest, src) {
clearArray(dest);
dest.push(...src);
return dest;
}
exports.replaceArray = replaceArray;
/**@remark side effect
* inplace operation
* @deprecated same as clear
* */
function takeAll(xs) {
const res = [].concat(xs);
exports.clear(xs);
return res;
}
exports.takeAll = takeAll;
function includes(x, xs) {
return xs.indexOf(x) !== -1;
}
exports.includes = includes;
/**
* only use `===` to compare
* @warning slow
* @return new array
* */
function unique(xs) {
return Array.from(new Set(xs));
}
exports.unique = unique;
function rightMost(n, xs) {
return xs.slice(xs.length - n, xs.length);
}
exports.rightMost = rightMost;
function leftMost(n, xs) {
return xs.slice(0, n);
}
exports.leftMost = leftMost;
/** inplace update */
function popN(n, xs) {
lang_1.forI(_ => xs.pop(), n);
}
exports.popN = popN;
/** inplace update */
function popUntilN(n, xs) {
lang_1.forI(_ => xs.pop(), xs.length - n);
}
exports.popUntilN = popUntilN;
/** inplace update */
function shiftN(n, xs) {
lang_1.forI(_ => xs.shift(), n);
}
exports.shiftN = shiftN;
/** inplace update */
function shiftUntilN(n, xs) {
lang_1.forI(_ => xs.shift(), xs.length - n);
}
exports.shiftUntilN = shiftUntilN;
function last(xs, skipCheck = false) {
if (!skipCheck && xs.length === 0) {
throw new TypeError('xs is not non-empty array');
}
return xs[xs.length - 1];
}
exports.last = last;
function maybeLast(xs) {
return maybe_1.Maybe.fromNullable(xs[xs.length - 1]);
}
exports.maybeLast = maybeLast;
function fromFileList(files) {
return lang_1.mapI(i => files.item(i), files.length);
}
exports.fromFileList = fromFileList;
function array_contains(xs, x) {
return xs.indexOf(x) !== -1;
}
exports.array_contains = array_contains;
function insert(xs, index, x) {
xs.splice(index, 0, x);
}
exports.insert = insert;
/**
* 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);
}
exports.insert_sorted = insert_sorted;
exports.defaultComparator = (a, b) => {
if (typeof a === 'string' && typeof b === 'string') {
return string_1.compare_string(a, b);
}
return compare_1.compare(a, b);
};
/**
*
* wrapper of slice, because it's confusing between slice and splice
*
* performance reference: https://jsperf.com/array-clone
* */
function cloneArray(xs) {
return xs.slice();
}
exports.cloneArray = cloneArray;
/**
* @return new array (not deep cloning elements)
* @deprecated use clone() and array.sort() explicitly is better
* */
function insertSortBy(xs, comparator) {
const res = new Array(xs.length);
xs.forEach(x => insert_sorted(res, comparator, x));
return res;
}
exports.insertSortBy = insertSortBy;
/**@deprecated*/
exports.sortBy = insertSortBy;
/**
* @return in-place sorted, original array
* */
function sort(xs, comparator = exports.defaultComparator) {
return xs.sort(comparator);
}
exports.sort = sort;
/**
* @remark inplace update
* @return original array
* */
function removeByIdx(xs, i) {
xs.splice(i, 1);
return xs;
}
exports.removeByIdx = removeByIdx;
/**
* @remark inplace update
* @return original array
* */
function remove(xs, x) {
const idx = xs.indexOf(x);
if (idx !== -1) {
xs.splice(idx, 1);
}
}
exports.remove = remove;
/**
* @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;
}
exports.removeBy = removeBy;
function nodup(xs) {
const s = new Set();
xs.forEach(x => s.add(x));
return Array.from(s.values());
}
exports.nodup = nodup;
/**
* 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;
}
exports.removeDup = removeDup;
/**
* inplace insert elements into the array
* @return old array
* */
function insertNoDup(acc, newXs) {
acc.push(...newXs);
return removeDup(acc);
}
exports.insertNoDup = insertNoDup;
/**
* 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;
}
exports.insertNoDupWithKey = insertNoDupWithKey;
/**
* inplace operation
* @return old array
* */
function removeDupByKey(xs, key) {
const t = {};
xs.map(x => (t[x[key]] = x));
replaceArray(xs, lang_1.objValues(t));
return xs;
}
exports.removeDupByKey = removeDupByKey;
/**
* inplace update
* @return old array
* */
function removeByKey(xs, key, keys) {
return replaceArray(xs, xs.filter(x => !array_contains(keys, x[key])));
}
exports.removeByKey = removeByKey;
/**
* including end
* */
function range(start, end, step = 1) {
const res = [];
for (let i = start; i <= end; i += step) {
res.push(i);
}
return res;
}
exports.range = range;
function repeat(x, n) {
const xs = new Array(n);
xs.fill(x);
return xs;
}
exports.repeat = repeat;
function filterByKey(src, key, keys) {
return src.filter(x => keys.indexOf(x[key]) !== -1);
}
exports.filterByKey = filterByKey;
function toArray(xs) {
// return mapI(i => xs[i], xs.length);
return Array.prototype.concat.apply([], xs);
}
exports.toArray = toArray;
function flatten(xss) {
return [].concat(...xss);
}
exports.flatten = flatten;
/**
* array.push is not monadic, this is a wrapper to make it monadic
* */
function push(res, ...xs) {
res.push(...xs);
return res;
}
exports.push = push;
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;
}
exports.binArray = binArray;
/**
* 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;
}
exports.binArrayBy = binArrayBy;
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];
}
exports.partitionArrayBy = partitionArrayBy;
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;
}
exports.zipArray = zipArray;
/**
* @description not same as Array.prototype.map!
* this will not skip uninitialized items
*
* Compare:
* new Array(3).map(x=>1) ~~> [<3 empty items>]
* map(new Array(3),x=>1) ~~> [ 1, 1, 1 ]
* */
function mapArray(xs, f) {
const res = new Array(xs.length);
for (let i = xs.length - 1; i >= 0; i--) {
res[i] = f(xs[i], i, xs);
}
return res;
}
exports.mapArray = mapArray;
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;
}
exports.countArray = countArray;
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);
}
exports.asyncCountArray = asyncCountArray;
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;
}
exports.max = max;
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;
}
exports.min = min;
function sum(xs) {
let acc = 0;
const n = xs.length;
for (let i = 0; i < n; i++) {
acc += xs[i];
}
return acc;
}
exports.sum = sum;
function sumByFunc(xs, mapper) {
let acc = 0;
const n = xs.length;
for (let i = 0; i < n; i++) {
acc += mapper(xs[i]);
}
return acc;
}
exports.sumByFunc = sumByFunc;
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;
}
exports.maxByFunc = maxByFunc;
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;
}
exports.minByFunc = minByFunc;
function maxByField(xs, key) {
let acc = xs[0];
const n = xs.length;
for (let i = 1; i < n; i++) {
const c = xs[i];
if (exports.defaultComparator(acc[key], c[key]) < 0) {
acc = c;
}
}
return acc;
}
exports.maxByField = maxByField;
function minByField(xs, key) {
let acc = xs[0];
const n = xs.length;
for (let i = 1; i < n; i++) {
const c = xs[i];
if (exports.defaultComparator(acc[key], c[key]) > 0) {
acc = c;
}
}
return acc;
}
exports.minByField = minByField;
function sumByField(xs, key) {
let acc = 0;
const n = xs.length;
for (let i = 0; i < n; i++) {
acc += xs[i][key];
}
return acc;
}
exports.sumByField = sumByField;
/**
* 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');
}
exports.median = median;
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;
}
exports.countElement = countElement;
function countAll(xs) {
const counts = new Map();
xs.forEach(x => map_1.incMap(counts, x));
return counts;
}
exports.countAll = countAll;
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;
}
exports.mode = mode;
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;
}
exports.shuffle = shuffle;
function shuffledBinArray(xs, binSize, nSwap) {
return binArray(shuffle(xs, nSwap), binSize);
}
exports.shuffledBinArray = shuffledBinArray;
function shuffledIndices(n) {
return shuffle(range(0, n - 1));
}
exports.shuffledIndices = shuffledIndices;
/**@deprecated typo in function name, renamed to shuffledIndices*/
exports.shuffledIndecies = shuffledIndices;
/**
* 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;
}
}
exports.genCombination = genCombination;
function flattenAll(xs) {
const ys = [];
flattenIoList(xs, ys);
return ys;
}
exports.flattenAll = flattenAll;
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 (;;) {
/* tslint:disable:no-unused-expression */
new Array(i);
/* tslint:enable:no-unused-expression */
i += i;
}
}
catch (e) {
let min = i / 2;
let max = i;
for (; min + 1 < max;) {
const m = Math.round((min + max) / 2);
try {
/* tslint:disable:no-unused-expression */
new Array(m);
/* tslint:enable:no-unused-expression */
min = m;
}
catch (e) {
max = m;
}
}
return min;
}
}
let MaxArraySize;
function getMaxArraySize() {
if (!MaxArraySize) {
MaxArraySize = _getMaxArraySize();
}
return MaxArraySize;
}
exports.getMaxArraySize = getMaxArraySize;
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;
}
exports.pushForward = pushForward;
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;
}
exports.pushBackward = pushBackward;
//# sourceMappingURL=array.js.map