export type MultiArray = N extends N ? number extends N ? T[] : _BuildTuple : never; type _BuildTuple< T, N extends number, R extends readonly unknown[], > = R["length"] extends N ? R : _BuildTuple; export function combinations( arr: T[], n: N, ): Array> { let res: Array> = []; arr.forEach((item, i) => { if (n === 1) return res.push([item] as any); const c = combinations(arr.slice(i + 1), n - 1); c.forEach((a) => res.push([item, ...a] as any)); }); return res; } export function multicombinations( arr: T[], n: N, ): Array> { let res: Array> = []; arr.forEach((item, i) => { if (n === 1) return res.push([item] as any); const c = multicombinations(arr.slice(i), n - 1); c.forEach((a) => res.push([item, ...a] as any)); }); return res; } export function unique(arr: T[]): T[] { return Array.from(new Set(arr)); } export function first(arr: T[]) { return arr[0]; } export function last(arr: T[]) { return arr[arr.length - 1]; } export function middle(arr: T[]) { return arr[Math.floor(arr.length / 2)]; } export function swap(a: number, b: number, arr: T[]): T[] { const newArr = [...arr]; const temp = newArr[a]; newArr[a] = newArr[b]!; newArr[b] = temp!; return newArr; } export function remove(arr: T[], idx: number): T[] { return arr.filter((_, i) => i !== idx); } export function sum(arr: number[]): number { return arr.reduce((acc, curr) => acc + curr, 0); } export function getIdxAt(idx: number, length: number) { if (idx >= 0) return idx % length; return length + (idx % length); } export function compareArr(arr1: unknown[], arr2: unknown[]): boolean { return arr1.every((item, i) => item === arr2[i]); }