Logo ArrayMixer

ArrayMixer is a tiny TypeScript-friendly utility (< 1 kB gzipped) for interleaving any number of arrays in a fully customizable order.
Powerful, dependency-free, and easy to use.

## Table of contents - [What's new in v1](#whats-new-in-v1) - [Documentation](#documentation) - [Installation](#installation) - [Playground](#playground) - [Quick start](#quick-start) - [API](#api) - [`arrayMixer(...entries, options?)`](#arraymixerentries-options) - [`MixEntry`](#mixentryt) - [`MixerOptions`](#mixeroptions) - [Examples](#examples) - [TypeScript support](#typescript-support) - [Contributing](#contributing) - [License](#license) ## What's new in v1 The previous `ArrayMixer(aliases, sequence)` API based on a string mini-DSL (`["2C", "4M"]`) was replaced by a clean, type-safe tuple-based API: ```ts // before (v0.x) ArrayMixer({ P: photos, A: ads }, ["2P", "1A"]); // after (v1.x) arrayMixer([2, photos], [1, ads]); ``` Why the change: - **No mini-DSL** — sequences are plain data, no string parsing. - **No aliases** — the source array is right there in the entry. - **Generic types** — the result type is inferred from the inputs. - **Options object** — opt into `limit`, `shuffle`, and `fill` strategies. ## Documentation Open the official docs page at [ArrayMixer Docs](./docs/) for package manager commands, ESM, CommonJS, browser UMD, and TypeScript notes. ## Installation ```bash pnpm add array-mixer ``` ```ts import { arrayMixer } from "array-mixer"; ``` CommonJS, ESM, and a UMD bundle are all shipped. For a ` ``` ## Playground Try the tuple API in the [ArrayMixer Playground](./playground/). ## Quick start Given two arrays, `photos` (12 items) and `ads` (6 items): ```ts photos.length === 12; // true ads.length === 6; // true ``` Interleave **2 photos** followed by **1 ad** until both arrays are consumed: ```ts const mixed = arrayMixer([2, photos], [1, ads]); ``` `mixed` will contain:
## API ### `arrayMixer(...entries, options?)` Reorder one or more arrays into a single array by interleaving chunks of each. ```ts function arrayMixer(...entries: MixEntry[]): T[]; function arrayMixer( ...args: [...MixEntry[], MixerOptions] ): T[]; ``` The optional `options` object is detected automatically as the **last** argument when it is not a `MixEntry` tuple. ### `MixEntry` ```ts type MixEntry = readonly [count: number, items: readonly T[]]; ``` A tuple with two fields: - `count` — how many items of this group to emit per round. Must be a positive integer. - `items` — the source array. ### `MixerOptions` ```ts interface MixerOptions { limit?: number; shuffle?: boolean; fill?: "repeat" | "skip" | "stop"; } ``` | Option | Default | Description | |-----------|-------------|-------------| | `limit` | sum of input lengths | Forces a fixed result length. Useful for infinite feeds. | | `shuffle` | `false` | Shuffles each input array (Fisher–Yates) before mixing. Inputs are not mutated. | | `fill` | `"repeat"` | What to do when an entry's source runs out: `"repeat"` cycles from the start, `"skip"` removes that group from further rounds, `"stop"` ends the result. | Invalid runtime input throws clear errors: - `count` must be a positive integer. - `limit`, when provided, must be a non-negative integer. - `fill`, when provided, must be `"repeat"`, `"skip"`, or `"stop"`. ## Examples ### 1) For every 7 photos display an ad ```ts arrayMixer([7, photos], [1, ads]); ``` ### 2) For every 4 paragraphs include 2 images ```ts arrayMixer([4, paragraphs], [2, images]); ``` ### 3) In a group of 8 related links, reserve positions 5–6 for sponsored ```ts arrayMixer([4, related], [2, sponsored], [2, related]); ``` ### 4) Display a list of songs with hits sprinkled in ```ts arrayMixer([10, songs], [2, hits]); ``` ### 5) Cycle puppies, kittens, and penguins in sequence ```ts const mixed = arrayMixer([1, puppies], [1, kittens], [1, penguins]); ``` | `puppies` | `kittens` | `penguins` | `mixed` | |---------------|---------------|---------------|------------------------------------------| | [🐶, 🐶, 🐶] | [🐱, 🐱, 🐱] | [🐧, 🐧, 🐧] | [🐶, 🐱, 🐧, 🐶, 🐱, 🐧, 🐶, 🐱, 🐧] | ### 6) 1 large photo for every 2 medium followed by 3 small ```ts arrayMixer([2, medium], [3, small], [1, large]); ```
### 7) Cap an infinite feed with `limit` ```ts arrayMixer([3, articles], [1, ads], { limit: 20 }); ``` The result is exactly 20 items long; arrays cycle as needed (`fill: "repeat"` is the default). ### 8) Stop when any source runs out ```ts arrayMixer( [2, [1, 2, 3, 4]], [1, [9]], { fill: "stop", limit: 100 }, ); // => [1, 2, 9, 3, 4] ``` ### 9) Drop exhausted groups, keep the rest going ```ts arrayMixer( [1, ["a", "b"]], [1, ["x", "y", "z", "w"]], { fill: "skip" }, ); // => ["a", "x", "b", "y", "z", "w"] ``` ### 10) Shuffle each source before mixing ```ts arrayMixer([2, ads], [5, articles], { shuffle: true }); ``` ## TypeScript support The result type is inferred from the inputs: ```ts const mixed = arrayMixer([2, ["red", "blue"]], [1, ["cat", "dog"]]); // mixed: string[] interface Photo { url: string } const photos: Photo[] = [/* ... */]; const ads: Photo[] = [/* ... */]; const feed = arrayMixer([2, photos], [1, ads]); // feed: Photo[] ``` ## Contributing You may contribute in many ways: new features, bug fixes, documentation improvements, or translations. See [CONTRIBUTING.md](CONTRIBUTING.md). ## License [MIT](LICENSE) — Jota Teles ## Special thanks - [Willian Ribeiro](https://github.com/willianribeiro) - [João Paulo](https://github.com/jpusp)