export class BetterMap<K, V> extends Map<K, V> { name: string; constructor(name?: string) { super(); this.name = typeof name === "string" ? name : "unknown items"; } array() { return this.map<V>((x: V) => x); } at(pos: number): V | undefined { if(pos > (this.size - 1)) pos = pos % (this.size - 1); if(pos < 0) pos = (this.size) + (pos % (this.size - 1)) const val = this.values() for(let i = 0; i < pos; ++i) { val.next() } return val.next().value } every(fn: (v: V, k: K) => boolean): boolean { for (const [k, v] of this.entries()) { if (!fn(v, k)) { return false; } } return true; } filter(fn: (v: V, k: K) => boolean): BetterMap<K, V> { const newColl = new BetterMap<K, V>(this.name); for (const [key, val] of this.entries()) { if (fn(val, key)) { newColl.set(key, val); } } return newColl; } find(fn: (v: V, k: K) => boolean): V | undefined { for (const [k, v] of this.entries()) { if (fn(v, k)) { return v; } } return undefined; } first(): V | undefined { return this.values().next().value; } firstKey(): K | undefined { return this.keys().next().value; } json(): Record<string, V> { const json: Record<string, V> = {}; for (const item of this.entries()) { Object.defineProperty(json, `${item[0]}`, { value: item[1], writable: true, }); } return json; } map<T>(fn: (v: V, k: K) => T): T[] | [] { const arr = []; for (const [k, v] of this.entries()) { arr.push(fn(v, k)); } return arr; } random(): V | undefined; random(count: number): V[]; random(count?: number): V | undefined | V[] | [] { if (!count) return this.#random(); const randomArr = []; for (let c = count; c > 0; --c) { const random = this.#random(); if (random) randomArr.push(random); } return randomArr; } #random(): V | undefined { const max = Math.floor(Math.random() * this.size); const iter = this.values(); for (let i = 0; i < max; ++i) { iter.next(); } return iter.next().value; } reduce<T>(fn: (acc: T, val: [K, V]) => T, first: T): T { const iter = this.entries(); let val; let result = first === undefined ? iter.next().value : first; while ((val = iter.next().value) !== undefined) { result = fn(result, val); } return result; } some(fn: (val: V, key: K) => boolean): boolean { for (const [k, v] of this.entries()) { if (fn(v, k)) { return true; } } return false; } sort(fn: (v1: V, v2: V, k1: K, k2: K) => number = () => 0): BetterMap<K, V> { const items = [...this.entries()]; items.sort((a, b) => fn(a[1], b[1], a[0], b[0])); const newColl = new BetterMap<K, V>(this.name); for (const [k, v] of items) { newColl.set(k, v); } return newColl; } toString(): string { return `[BetterMap[${this.size}] of <${this.name}>]`; } toJSON(): Record<string, V> { return this.json(); } static from<K1, V1>(data: Map<K1, V1> | [K1, V1][]): BetterMap<K1, V1> { const returnMap = new BetterMap<K1, V1>(); if (data instanceof Map) { data.forEach((v: V1, k: K1) => returnMap.set(k, v)); } if (Array.isArray(data)) { data.forEach(([k, v]) => returnMap.set(k, v)); } return returnMap; }}