scats
Version:
Useful scala classes in typescript
378 lines (377 loc) • 10.3 kB
JavaScript
import { Collection, HashMap, none, option, some } from './index.js';
export class ArrayIterable {
[Symbol.iterator]() {
let i = 0;
const items = this.toArray;
return {
next() {
if (i < items.length) {
const value = items[i];
i = i + 1;
return {
value: value,
done: false
};
}
else {
return {
value: undefined,
done: true
};
}
}
};
}
foreach(job) {
this.toArray.forEach(x => job(x));
}
contains(item) {
return this.toArray.indexOf(item) >= 0;
}
forall(p) {
return this.toArray.every(i => p(i));
}
exists(p) {
return this.toArray.find(i => p(i)) !== undefined;
}
find(p) {
return option(this.toArray.find(i => p(i)));
}
count(p) {
let res = 0;
this.toArray.forEach(i => {
if (p(i)) {
res++;
}
});
return res;
}
get isEmpty() {
return this.size <= 0;
}
get nonEmpty() {
return !this.isEmpty;
}
get size() {
return this.toArray.length;
}
reduce(op) {
return this.reduceLeft(op);
}
reduceOption(op) {
return this.reduceLeftOption(op);
}
get headOption() {
return this.isEmpty ? none : some(this.head);
}
get head() {
if (this.isEmpty) {
throw new Error('head on empty collection');
}
else {
return this.toArray[0];
}
}
get lastOption() {
return this.isEmpty ? none : some(this.last);
}
get last() {
if (this.isEmpty) {
throw new Error('empty.last');
}
else {
return this.toArray[this.size - 1];
}
}
reduceLeft(op) {
if (this.isEmpty) {
throw new Error('empty.reduceLeft');
}
const array = this.toArray;
let acc = array[0];
if (array.length > 1) {
for (let i = 1; i < array.length; i++) {
acc = op(acc, array[i]);
}
}
return acc;
}
reduceLeftOption(op) {
return this.isEmpty ? none : some(this.reduceLeft(op));
}
foldRight(initial) {
return (op) => {
return new Collection(this.toArray)
.reverse
.foldLeft(initial)((a, n) => op(n, a));
};
}
reduceRight(op) {
if (this.isEmpty) {
throw new Error('empty.reduceRight');
}
let acc = this.last;
const array = this.toArray.reverse();
if (array.length > 1) {
for (let i = 1; i < array.length; i++) {
acc = op(acc, array[i]);
}
}
return acc;
}
reduceRightOption(op) {
return this.isEmpty ? none : some(this.reduceRight(op));
}
foldLeft(initial) {
return (op) => {
return this.toArray.reduce((a, n) => op(a, n), initial);
};
}
fold(initial) {
return this.foldLeft(initial);
}
groupBy(field) {
return this.foldLeft(HashMap.empty)((acc, next) => {
const key = field(next);
const existing = acc.get(key).getOrElseValue(Collection.empty);
return acc.set(key, new Collection(existing.toArray.concat(next)));
});
}
minBy(toNumber) {
if (this.isEmpty) {
throw new Error('empty.minBy');
}
else {
let res = this.head;
let min = toNumber(res);
this.toArray.forEach(i => {
const next = toNumber(i);
if (next < min) {
res = i;
min = next;
}
});
return res;
}
}
minByOption(toNumber) {
return this.isEmpty ? none : some(this.minBy(toNumber));
}
maxBy(toNumber) {
if (this.isEmpty) {
throw new Error('empty.maxBy');
}
else {
let res = this.head;
let max = toNumber(res);
this.toArray.forEach(i => {
const next = toNumber(i);
if (next > max) {
res = i;
max = next;
}
});
return res;
}
}
maxByOption(toNumber) {
return this.isEmpty ? none : some(this.maxBy(toNumber));
}
partition(p) {
const array = this.toArray;
const first = array.filter(i => p(i));
const second = array.filter(i => !p(i));
return [this.fromArray(first), this.fromArray(second)];
}
take(n) {
const items = this.toArray;
return items.length > n ? this.fromArray(items.slice(0, n)) : this;
}
takeRight(n) {
const array = this.toArray;
return array.length > n ? this.fromArray(array.slice(array.length - n, array.length)) : this;
}
takeWhile(p) {
const array = this.toArray;
let res = true;
let i = 0;
for (; res && i < array.length; i++) {
res = p(array[i]);
}
if (res) {
return this;
}
else {
return this.take(i - 1);
}
}
drop(n) {
const array = this.toArray;
if (n >= array.length) {
return this.fromArray([]);
}
else if (n === 0) {
return this;
}
else {
return this.fromArray(array.slice(n, array.length));
}
}
dropRight(n) {
const array = this.toArray;
if (n >= array.length) {
return this.fromArray([]);
}
else if (n === 0) {
return this;
}
else {
return this.fromArray(array.slice(0, array.length - n));
}
}
dropWhile(p) {
const array = this.toArray;
let res = true;
let i = 0;
for (; res && i < array.length; i++) {
res = p(array[i]);
}
if (res) {
return this.fromArray([]);
}
else {
return this.drop(i - 1);
}
}
sliding(length, step = 1) {
if (this.isEmpty) {
return Collection.empty;
}
else {
const itemsSize = this.size;
if (itemsSize <= length) {
return Collection.of(this);
}
else {
const result = [];
let left = 0;
let done = false;
let right = length;
const items = this.toArray;
while (!done) {
done = right >= itemsSize;
result.push(this.fromArray(items.slice(left, right)));
left += step;
right = left + length;
}
return new Collection(result);
}
}
}
grouped(length) {
return this.sliding(length, length);
}
mkString(separator = '') {
return this.toArray.join(separator);
}
sum(elementToNum) {
if (this.isEmpty) {
return 0;
}
else {
return this.toArray.reduce((acc, next) => acc + elementToNum(next), 0);
}
}
filter(p) {
return this.fromArray(this.toArray.filter(i => p(i)));
}
filterNot(p) {
return this.fromArray(this.toArray.filter(i => !p(i)));
}
splitAt(n) {
return [this.take(n), this.drop(n)];
}
span(p) {
return [this.takeWhile(p), this.dropWhile(p)];
}
get init() {
if (this.isEmpty)
throw new Error('empty.init');
return this.dropRight(1);
}
get tail() {
if (this.isEmpty)
throw new Error('empty.tail');
return this.drop(1);
}
groupMap(key) {
return (value) => {
return this.foldLeft(HashMap.empty)((acc, next) => {
const nextKey = key(next);
const existingColl = acc.getOrElse(nextKey, () => Collection.empty);
const updatedColl = existingColl.appended(value(next));
return acc.updated(nextKey, updatedColl);
});
};
}
groupMapReduce(key) {
return (value) => {
return (reduce) => {
return this.foldLeft(HashMap.empty)((acc, next) => {
const nextKey = key(next);
const nextValue = value(next);
return acc.updated(nextKey, acc.get(nextKey).map(e => reduce(e, nextValue)).getOrElseValue(nextValue));
});
};
};
}
scan(z) {
return this.scanLeft(z);
}
scanLeft(z) {
return (op) => {
const res = [z];
let acc = z;
this.toArray.forEach(i => {
acc = op(acc, i);
res.push(acc);
});
return this.fromArray(res);
};
}
scanRight(z) {
return (op) => {
const res = [z];
let acc = z;
this.toArray.reverse().forEach(i => {
acc = op(acc, i);
res.push(acc);
});
return this.fromArray(res.reverse());
};
}
get zipWithIndex() {
const res = [];
const array = this.toArray;
for (let i = 0; i < array.length; i++) {
res.push([array[i], i]);
}
return new Collection(res);
}
get tails() {
const array = this.toArray;
const res = [];
for (let i = 0; i <= array.length; i++) {
res.push(this.takeRight(array.length - i));
}
return new Collection(res);
}
get inits() {
const array = this.toArray;
const res = [];
for (let i = 0; i <= array.length; i++) {
res.push(this.take(array.length - i));
}
return new Collection(res);
}
}