Project Awesome project awesome

teles/array-mixer

Clean project logo, badges. Table of contents. Contribution section. Many illustrated examples.

Package 42 stars GitHub


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

The previous ArrayMixer(aliases, sequence) API based on a string mini-DSL (["2C", "4M"]) was replaced by a clean, type-safe tuple-based API:

// 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.

Installation

pnpm add array-mixer
import { arrayMixer } from "array-mixer";

CommonJS, ESM, and a UMD bundle are all shipped. For a <script> tag:

<script src="https://unpkg.com/array-mixer/release/array-mixer.umd.js"></script>
<script>
  const mixed = ArrayMixer.arrayMixer([2, photos], [1, ads]);
</script>

Playground

Try the tuple API with emoji cards in the ArrayMixer Playground.

Quick start

Given two arrays, photos (12 items) and ads (6 items):

photos.length === 12; // true
ads.length === 6;     // true

Interleave 2 photos followed by 1 ad until both arrays are consumed:

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.

function arrayMixer<T>(...entries: MixEntry<T>[]): T[];
function arrayMixer<T>(
  ...args: [...MixEntry<T>[], MixerOptions]
): T[];

The optional options object is detected automatically as the last argument when it is not a MixEntry tuple.

MixEntry<T>

type MixEntry<T> = 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

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

arrayMixer([7, photos], [1, ads]);

2) For every 4 paragraphs include 2 images

arrayMixer([4, paragraphs], [2, images]);

3) In a group of 8 related links, reserve positions 5–6 for sponsored

arrayMixer([4, related], [2, sponsored], [2, related]);

4) Display a list of songs with hits sprinkled in

arrayMixer([10, songs], [2, hits]);

5) Cycle puppies, kittens, and penguins in sequence

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

arrayMixer([2, medium], [3, small], [1, large]);

7) Cap an infinite feed with limit

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

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

arrayMixer(
  [1, ["a", "b"]],
  [1, ["x", "y", "z", "w"]],
  { fill: "skip" },
);
// => ["a", "x", "b", "y", "z", "w"]

10) Shuffle each source before mixing

arrayMixer([2, ads], [5, articles], { shuffle: true });

TypeScript support

The result type is inferred from the inputs:

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.

License

MIT — Jota Teles

Special thanks

Back to Readme