Skip to content

Instantly share code, notes, and snippets.

@masaedw
Created August 7, 2020 04:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save masaedw/4893cc5276818e73fa048d890ad7cd47 to your computer and use it in GitHub Desktop.
Save masaedw/4893cc5276818e73fa048d890ad7cd47 to your computer and use it in GitHub Desktop.
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