UNPKG

scats

Version:

Useful scala classes in typescript

375 lines (374 loc) 10.1 kB
import { HashMap, HashSet } from './index.js'; import { ArrayIterable } from './array-iterable.js'; export class ArrayBackedCollection extends ArrayIterable { checkWithinBounds(lo, hi) { if (lo < 0) throw new Error(`$lo is out of bounds (min 0, max ${this.items.length - 1})`); if (hi > this.size) throw new Error(`$lo is out of bounds (min 0, max ${this.items.length - 1})`); } get reverse() { return this.fromArray(this.items.reverse()); } get toArray() { return this.items; } get(index) { this.checkWithinBounds(index, index + 1); return this.items[index]; } get toSet() { return HashSet.of(...this.items); } indexOf(item) { return this.items.indexOf(item); } get distinct() { return this.fromArray(Array.from(new Set(this.items))); } distinctBy(key) { const keys = new Set(); const res = []; this.foreach(item => { const currentKey = key(item); if (!keys.has(currentKey)) { keys.add(currentKey); res.push(item); } }); return this.fromArray(res); } appended(item) { return this.fromArray(this.items.concat([item])); } appendedAll(other) { return this.fromArray(this.items.concat([...other])); } prepended(item) { return this.fromArray([item].concat(this.items)); } prependedAll(other) { return this.fromArray(Array.from(other).concat(this.items)); } concat(other) { return this.appendedAll(other); } slice(from, until) { return this.fromArray(this.items.slice(from, until)); } sort(param) { return this.fromArray(this.items.slice(0).sort(param)); } sortBy(fieldToNumber) { return this.sort(((a, b) => fieldToNumber(a) - fieldToNumber(b))); } get length() { return this.size; } } export class Collection extends ArrayBackedCollection { items; constructor(items) { super(); this.items = items; } static empty = new Collection([]); fromArray(array) { if (!array || array.length <= 0) { return Nil; } else { return new Collection(array); } } static of(...items) { return new Collection(items); } static from(elements) { return new Collection(Array.from(elements)); } static fill(len) { return function (elem) { const res = new Array(len); for (let i = 0; i < len; i++) { res[i] = elem(i); } return new Collection(res); }; } map(f) { return new Collection(this.items.map(i => f(i))); } flatMap(f) { let res = []; this.items.forEach(i => { res = res.concat(f(i).items); }); return new Collection(res); } flatMapOption(f) { const res = []; this.items.forEach(i => { f(i).foreach(v => { res.push(v); }); }); return new Collection(res); } async mapPromise(f) { const res = []; for (let i = 0; i < this.items.length; i++) { res.push(await f(this.items[i])); } return new Collection(res); } async mapPromiseAll(f) { return new Collection(await Promise.all(this.items.map(i => f(i)))); } async flatMapPromise(f) { let res = []; for (let i = 0; i < this.items.length; i++) { const item = this.items[i]; res = res.concat((await f(item)).items); } return new Collection(res); } async flatMapPromiseAll(f) { return (await this.mapPromiseAll(f)).flatten(); } flatten() { const res = []; this.items.forEach(i => { if (i instanceof Collection) { res.push(...i.items); } else { res.push(i); } }); return new Collection(res); } get toBuffer() { return new ArrayBuffer(this.items); } toMap(mapper) { return HashMap.of(...this.map(mapper).toArray); } zip(that) { const res = []; for (let i = 0; i < Math.min(this.size, that.size); i++) { res.push([this.items[i], that.items[i]]); } return new Collection(res); } zipAll(that, thisElem, thatElem) { const res = []; for (let i = 0; i < Math.max(this.size, that.size); i++) { res.push([ i < this.items.length ? this.items[i] : thisElem, i < that.items.length ? that.items[i] : thatElem ]); } return new Collection(res); } } export const Nil = Collection.empty; export class ArrayBuffer extends ArrayBackedCollection { items; static get empty() { return new ArrayBuffer([]); } constructor(items = []) { super(); this.items = items; } static of(...elements) { return new ArrayBuffer(elements); } static from(elements) { return new ArrayBuffer(Array.from(elements)); } static fill(len) { return function (elem) { const res = new Array(len); for (let i = 0; i < len; i++) { res[i] = elem(i); } return new ArrayBuffer(res); }; } fromArray(array) { if (!array || array.length <= 0) { return new ArrayBuffer([]); } else { return new ArrayBuffer(array); } } normalized(n) { return Math.min(Math.max(n, 0), this.length); } update(index, element) { this.checkWithinBounds(index, index + 1); this.items[index] = element; } set(index, element) { this.update(index, element); } clear() { this.items.length = 0; } append(element) { this.items.push(element); return this; } appendAll(elements) { this.items.push(...elements); return this; } prepend(element) { this.items.unshift(element); return this; } prependAll(elements) { this.items.unshift(...elements); return this; } insert(idx, element) { this.checkWithinBounds(idx, idx); this.items.splice(idx, 0, element); } insertAll(idx, elements) { this.checkWithinBounds(idx, idx); this.items.splice(idx, 0, ...elements); } remove(index, count = 1) { if (count > 0) { this.checkWithinBounds(index, index + 1); this.items.splice(index, count); } else if (count < 0) { throw new Error('removing negative number of elements: ' + count); } } subtractOne(element) { const i = this.items.indexOf(element); if (i != -1) { this.remove(i); } return this; } subtractAll(elements) { if (elements === this || elements === this.items) { const buf = new ArrayBuffer(Array.from(elements)); buf.foreach(e => this.subtractOne(e)); } else { for (const element of elements) { this.subtractOne(element); } } return this; } sort(compareFn) { this.items.sort(compareFn); return this; } filterInPlace(p) { let i = 0, j = 0; while (i < this.size) { if (p(this.items[i])) { if (i != j) { this.items[j] = this.items[i]; } j += 1; } i += 1; } if (i == j) { return this; } else { return this.takeInPlace(j); } } dropInPlace(n) { this.remove(0, this.normalized(n)); return this; } dropRightInPlace(n) { const norm = this.normalized(n); this.remove(this.length - norm, norm); return this; } takeInPlace(n) { const norm = this.normalized(n); this.remove(norm, this.length - norm); return this; } takeRightInPlace(n) { this.remove(0, this.length - this.normalized(n)); return this; } sliceInPlace(start, end) { return this.takeInPlace(end).dropInPlace(start); } get toCollection() { return new Collection(this.items.slice(0)); } flatMap(f) { let res = []; this.items.forEach(i => { res = res.concat(f(i).items); }); return new ArrayBuffer(res); } flatMapOption(f) { const res = []; this.items.forEach(i => { f(i).foreach(v => { res.push(v); }); }); return new ArrayBuffer(res); } async flatMapPromise(f) { let res = []; for (let i = 0; i < this.items.length; i++) { const item = this.items[i]; res = res.concat((await f(item)).items); } return new ArrayBuffer(res); } map(f) { return new ArrayBuffer(this.items.map(i => f(i))); } async mapPromise(f) { const res = []; for (let i = 0; i < this.items.length; i++) { res.push(await f(this.items[i])); } return new ArrayBuffer(res); } async mapPromiseAll(f) { return new ArrayBuffer(await Promise.all(this.items.map(i => f(i)))); } async flatMapPromiseAll(f) { return (await this.mapPromiseAll(f)).flatten(); } flatten() { const res = []; this.items.forEach(i => { if (i instanceof ArrayBuffer) { res.push(...i.items); } else { res.push(i); } }); return new ArrayBuffer(res); } toMap(mapper) { return HashMap.of(...this.map(mapper).toArray); } }