UNPKG

scats

Version:

Useful scala classes in typescript

378 lines (377 loc) 10.3 kB
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); } }