scats
Version:
Useful scala classes in typescript
375 lines (374 loc) • 10.1 kB
JavaScript
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);
}
}