Skip to content

Instantly share code, notes, and snippets.

@xmodar
Last active March 21, 2022 01:53
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 xmodar/d3a17bf51b8399534c5f8d27104a2a38 to your computer and use it in GitHub Desktop.
Save xmodar/d3a17bf51b8399534c5f8d27104a2a38 to your computer and use it in GitHub Desktop.
JavaScript utilities to mimic Python
/** {@link https://gist.github.com/xmodar/d3a17bf51b8399534c5f8d27104a2a38} */
export const operator = {
lt: <T>(a: T, b: T) => a < b,
le: <T>(a: T, b: T) => a <= b,
eq: <T>(a: T, b: T) => a === b,
ne: <T>(a: T, b: T) => a !== b,
ge: <T>(a: T, b: T) => a >= b,
gt: <T>(a: T, b: T) => a > b,
not: <T>(a: T) => !a,
abs: (a: number) => Math.abs(a),
add: (a: number, b: number) => a + b,
and_: (a: number, b: number) => a & b,
floordiv: (a: number, b: number) => (a / b) >> 0,
inv: <T>(a: T) => ~a,
lshift: (a: number, b: number) => a << b,
mod: (a: number, b: number) => a % b,
mul: (a: number, b: number) => a * b,
neg: <T>(a: T) => -a,
or_: (a: number, b: number) => a | b,
pow: (a: number, b: number) => a ** b,
rshift: (a: number, b: number) => a >> b,
sub: (a: number, b: number) => a - b,
truediv: (a: number, b: number) => a / b,
xor: (a: number, b: number) => a ^ b,
};
export function list<T>(iterable: Iterable<T> | undefined = undefined): T[] {
return iterable === undefined ? [] : Array.from(iterable);
}
export function* iter<T>(iterable: Iterable<T>): Generator<T> {
for (const value of iterable) yield value;
}
export function* range(
start: number,
stop: number | undefined = undefined,
step = 1,
): Generator<number> {
if (step === 0) throw new Error('step cannot be zero');
if (stop === undefined) [start, stop] = [0, start];
const notDone = step > 0 ? operator.lt : operator.gt;
while (notDone(start, stop)) {
yield start;
start += step;
}
}
export function* enumerate<T>(
iterable: Iterable<T>,
start = 0,
): Generator<[number, T]> {
for (const value of iterable) yield [start++, value];
}
export function* reversed<T>(iterable: T[]): Generator<T> {
for (let i = iterable.length - 1; i >= 0; i--) yield iterable[i];
}
export function* map<S, T>(
callable: (a: S) => T,
iterable: Iterable<S>,
): Generator<T> {
for (const value of iterable) yield callable(value);
}
export function* filter<T>(
callable: (a: T) => boolean,
iterable: Iterable<T>,
): Generator<T> {
for (const value of iterable) if (callable(value)) yield value;
}
export function reduce<S, T>(
callable: (a: T, b: S) => T,
iterable: Iterable<S>,
initial: T | undefined = undefined,
): T {
let first = initial === undefined;
for (const value of iterable) {
if (first) {
first = false;
initial = value as unknown as T;
} else {
initial = callable(initial as T, value);
}
}
if (initial === undefined) throw new Error('provide at least one value');
return initial;
}
export function sum(iterable: Iterable<number>, start = 0): number {
for (const value of iterable) start += value;
return start;
}
export function prod(iterable: Iterable<number>, start = 1): number {
for (const value of iterable) start *= value;
return start;
}
export function all<T>(iterable: Iterable<T>): boolean {
for (const value of iterable) if (!value) return false;
return true;
}
export function any<T>(iterable: Iterable<T>): boolean {
for (const value of iterable) if (value) return true;
return false;
}
type Zip<T extends Iterable<any>[]> = {
[I in keyof T]: T[I] extends Iterable<infer E> ? E : never;
};
export function* zip<T extends Iterable<any>[]>(...iterables: T) {
if (iterables.length === 0) return;
const _iterables = list(map(iter, iterables));
while (true) {
const pair = [];
for (const iterable of _iterables) {
const item = iterable.next();
if (item.done) return;
pair.push(item.value);
}
yield pair as Zip<T>;
}
}
export function* product<T extends any[][]>(...iterables: T) {
const count = [1];
for (const iterable of reversed(iterables)) {
count.unshift(iterable.length * count[0]);
}
for (const i of range(count.shift() as number)) {
const pair = [];
for (const [j, iterable] of zip(count, iterables as any[][])) {
pair.push(iterable[Math.floor(i / j) % iterable.length]);
}
yield pair as Zip<T>;
}
}
export function uuid4() {
// https://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid
const randByte = () => crypto.getRandomValues(new Uint8Array(1))[0];
const shuffle = (c: number) => c ^ (randByte() & (15 >> (c / 4)));
const randHex = (c: string) => shuffle(parseInt(c)).toString(16);
return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, randHex);
}
export function uuid4Int() {
return BigInt('0x' + uuid4().replace(/-/g, ''));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment