Created
August 7, 2020 04:20
-
-
Save masaedw/4893cc5276818e73fa048d890ad7cd47 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export function tuple<T1, T2>(t1: T1, t2: T2): [T1, T2] { | |
return [t1, t2]; | |
} | |
export type Func<T, R> = (t: T) => R; | |
export type KeyValuesPair<K, V> = [K, V[]]; | |
export const groupBy = Symbol(); | |
export const toMapBy = Symbol(); | |
export const toMap = Symbol(); | |
export const unique = Symbol(); | |
export const compact = Symbol(); | |
export const fastJoin = Symbol(); | |
export const filterIn = Symbol(); | |
export const filterNotIn = Symbol(); | |
declare global { | |
interface Array<T> { | |
[groupBy]<K>(this: T[], keySelector: Func<T, K>): KeyValuesPair<K, T>[]; | |
[groupBy]<K, V>( | |
this: T[], | |
keySelector: Func<T, K>, | |
valueSelector: Func<T, V> | |
): KeyValuesPair<K, V>[]; | |
[toMapBy]<K>(this: T[], keySelector: Func<T, K>): Map<K, T>; | |
[toMapBy]<K, V>( | |
this: T[], | |
keySelector: Func<T, K>, | |
valueSelector: Func<T, V> | |
): Map<K, V>; | |
[toMap]<K, V>(this: [K, V][]): Map<K, V>; | |
[unique](this: T[]): T[]; | |
[compact](this: T[]): NonNullable<T>[]; | |
[fastJoin](this: string[], separator?: string): string; | |
[filterIn](this: T[], others: Iterable<T>): Array<T>; | |
[filterNotIn](this: T[], others: Iterable<T>): Array<T>; | |
} | |
} | |
Array.prototype[groupBy] = function <T, K, V>( | |
this: T[], | |
keySelector: Func<T, K>, | |
valueSelector?: Func<T, V> | |
): KeyValuesPair<K, V | T>[] { | |
const map = new Map<K, (V | T)[]>(); | |
const keys = [] as K[]; | |
this.forEach((x) => { | |
const key = keySelector(x); // to let result be stable order | |
const collection = map.get(key); | |
if (!collection) { | |
map.set(key, [valueSelector ? valueSelector(x) : x]); | |
keys.push(key); | |
} else { | |
collection.push(valueSelector ? valueSelector(x) : x); | |
} | |
}); | |
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | |
return keys.map((key) => tuple(key, map.get(key)!)); | |
}; | |
Array.prototype[toMapBy] = function <T, K, V>( | |
this: T[], | |
keySelector: Func<T, K>, | |
valueSelector?: Func<T, V> | |
): Map<K, V | T> { | |
return new Map( | |
this.map((x) => | |
tuple(keySelector(x), valueSelector ? valueSelector(x) : x) | |
) | |
); | |
}; | |
Array.prototype[toMap] = function <K, V>(this: [K, V][]): Map<K, V> { | |
return new Map(this); | |
}; | |
Array.prototype[unique] = function <T>(this: T[]): T[] { | |
const set = new Set<T>(); | |
const result = [] as T[]; | |
for (const x of this) { | |
if (set.has(x)) { | |
continue; | |
} | |
set.add(x); | |
result.push(x); | |
} | |
return result; | |
}; | |
Array.prototype[compact] = function <T>(this: (T | undefined)[]): T[] { | |
return this.filter(isTruthy); | |
}; | |
Array.prototype[fastJoin] = function (this: string[], separator = ","): string { | |
let output = ""; | |
const len = this.length; | |
for (let i = 0; i < len; i++) { | |
output += this[i]; | |
if (i < len - 1) { | |
output += separator; | |
} | |
} | |
return output; | |
}; | |
Array.prototype[filterIn] = function <T>( | |
this: T[], | |
others: Iterable<T> | |
): Array<T> { | |
const set = others instanceof Set ? (others as Set<T>) : new Set(others); | |
return this.filter((x) => set.has(x)); | |
}; | |
Array.prototype[filterNotIn] = function <T>( | |
this: T[], | |
others: Iterable<T> | |
): Array<T> { | |
const set = others instanceof Set ? (others as Set<T>) : new Set(others); | |
return this.filter((x) => !set.has(x)); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment