Skip to content

zip

Edit

Groups values that share the same index across multiple arrays.

zip.ts
export type ZipMode = "shortest" | "longest";
export type Zipped<Arrays extends readonly (readonly unknown[])[]> = {
-readonly [
Index in keyof Arrays
]: Arrays[Index] extends readonly (infer Value)[] ? Value : never;
};
export type ZippedLongest<Arrays extends readonly (readonly unknown[])[]> = {
-readonly [
Index in keyof Arrays
]: Arrays[Index] extends readonly (infer Value)[] ? Value | undefined : never;
};
/** Groups values at matching indexes across multiple arrays. */
export const zip = <
const Arrays extends readonly (readonly unknown[])[],
const Mode extends ZipMode = "shortest",
>(
arrays: Arrays,
{ mode = "shortest" as Mode }: { mode?: Mode } = {},
): Array<Mode extends "longest" ? ZippedLongest<Arrays> : Zipped<Arrays>> => {
if (mode !== "shortest" && mode !== "longest") {
throw new RangeError("mode must be shortest or longest");
}
const denseArrays: unknown[][] = [];
for (let arrayIndex = 0; arrayIndex < arrays.length; arrayIndex += 1) {
if (!Object.hasOwn(arrays, arrayIndex)) {
throw new TypeError("arrays must not contain empty slots");
}
const array = arrays[arrayIndex];
if (!Array.isArray(array)) {
throw new TypeError("arrays must contain only arrays");
}
const dense: unknown[] = [];
for (let index = 0; index < array.length; index += 1) {
if (!Object.hasOwn(array, index)) {
throw new TypeError("input arrays must not contain empty slots");
}
dense.push(array[index]);
}
denseArrays.push(dense);
}
if (denseArrays.length === 0) return [];
const lengths = denseArrays.map((array) => array.length);
const rowCount =
mode === "longest" ? Math.max(...lengths) : Math.min(...lengths);
const rows: unknown[][] = [];
for (let index = 0; index < rowCount; index += 1) {
rows.push(denseArrays.map((array) => array[index]));
}
return rows as Array<
Mode extends "longest" ? ZippedLongest<Arrays> : Zipped<Arrays>
>;
};
Terminal
wget -O src/lib/zip.ts https://raw.githubusercontent.com/jrTilak/lazykit/HEAD/registry/functions/zip.ts
zip.example.ts
import { zip } from "./zip";
const arrays = [[1, 2, 3], ["a", "b", "c", "d"]];
const result = zip(arrays);
console.log(result);
// Output: [[1, "a"], [2, "b"], [3, "c"]]
zip.2.example.ts
import { zip } from "./zip";
const arrays = [[1, 2, 3], ["x", "y"]];
const strictResult = zip(arrays);
console.log(strictResult);
// Output: [[1, "x"], [2, "y"]]
zip.3.example.ts
import { zip } from "./zip";
const arrays = [[1, 2, 3], ["a", "b", "c", "d"], [true, false]];
const result = zip(arrays, { mode: "longest" });
console.log(result);
// Output: [[1, "a", true], [2, "b", false], [3, "c", undefined], [undefined, "d", undefined]]
zip.4.example.ts
import { zip } from "./zip";
const arrays = [[1, 2, 3], ["x", "y", "z"], [10, 20]];
const strictResult = zip(arrays);
console.log(strictResult);
// Output: [[1, "x", 10], [2, "y", 20]]
  • arrays (readonly (readonly unknown[])[]) — Dense arrays whose values should be grouped by index. Sparse outer or inner arrays are rejected.
  • options.mode ("shortest" | "longest", default: "shortest") — Stops at the shortest input or continues to the longest and inserts undefined for missing values.

An array of tuples, one for each included index.