{"id":15357133,"url":"https://github.com/chocolateboy/enumerator","last_synced_at":"2025-10-30T15:17:51.218Z","repository":{"id":53787622,"uuid":"325338877","full_name":"chocolateboy/enumerator","owner":"chocolateboy","description":"Generate a series of tuples in lexicographical order","archived":false,"fork":false,"pushed_at":"2021-06-05T16:13:12.000Z","size":384,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-17T21:12:22.865Z","etag":null,"topics":["alphabet","cartesian-product","combinatorics","cross-product","enumerable","generator","iterable","lexicographic","lexicographical","n-tuple","odometer","permutation","permutations","sequence","symbols","tuple"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chocolateboy.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-12-29T16:47:02.000Z","updated_at":"2021-11-02T22:20:17.000Z","dependencies_parsed_at":"2022-09-04T17:11:15.474Z","dependency_job_id":null,"html_url":"https://github.com/chocolateboy/enumerator","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chocolateboy%2Fenumerator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chocolateboy%2Fenumerator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chocolateboy%2Fenumerator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chocolateboy%2Fenumerator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chocolateboy","download_url":"https://codeload.github.com/chocolateboy/enumerator/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246531986,"owners_count":20792735,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alphabet","cartesian-product","combinatorics","cross-product","enumerable","generator","iterable","lexicographic","lexicographical","n-tuple","odometer","permutation","permutations","sequence","symbols","tuple"],"created_at":"2024-10-01T12:33:22.123Z","updated_at":"2025-10-30T15:17:46.169Z","avatar_url":"https://github.com/chocolateboy.png","language":"JavaScript","readme":"# enumerator\n\n[![Build Status](https://github.com/chocolateboy/enumerator/workflows/test/badge.svg)](https://github.com/chocolateboy/enumerator/actions?query=workflow%3Atest)\n[![NPM Version](https://img.shields.io/npm/v/@chocolatey/enumerator.svg)](https://www.npmjs.org/package/@chocolatey/enumerator)\n\n\u003c!-- TOC --\u003e\n\n- [NAME](#name)\n- [FEATURES](#features)\n- [INSTALLATION](#installation)\n- [SYNOPSIS](#synopsis)\n- [DESCRIPTION](#description)\n  - [Why?](#why)\n- [EXPORTS](#exports)\n  - [enumerate](#enumerate)\n  - [enumerator](#enumerator)\n  - [unfold](#unfold)\n- [EXAMPLES](#examples)\n  - [Generating passwords](#generating-passwords)\n  - [Combining options](#combining-options)\n- [DEVELOPMENT](#development)\n- [COMPATIBILITY](#compatibility)\n- [SEE ALSO](#see-also)\n- [VERSION](#version)\n- [AUTHOR](#author)\n- [COPYRIGHT AND LICENSE](#copyright-and-license)\n\n\u003c!-- TOC END --\u003e\n\n# NAME\n\nenumerator - generate a series of tuples in lexicographical order\n\n# FEATURES\n\n- no dependencies\n- ~500 B minified + gzipped\n- fully typed (TypeScript)\n- CDN builds (UMD): [jsDelivr][], [unpkg][]\n\n# INSTALLATION\n\n```\n$ npm install @chocolatey/enumerator\n```\n\n# SYNOPSIS\n\n```javascript\nimport { enumerate, enumerator } from '@chocolatey/enumerator'\n\nconst bits = [0, 1]\nconst words = ['foo', 'bar', 'baz', 'quux']\n\n// generator\nfor (const value of enumerator([words, bits])) {\n    console.log(value) // [\"foo\", 0], [\"foo\", 1], [\"bar\", 0] ... [\"quux\", 1]\n}\n\n// array\nenumerate(bits, 2) // [[0, 0], [0, 1], [1, 0], [1, 1]]\n```\n\n# DESCRIPTION\n\nEnumerator generates a series of tuples in lexicographical order. Each tuple is\nan array of values drawn from a custom alphabet for each position. Values can\nbe of any type.\n\nThe mechanism for generating the values is the same as an odometer, i.e. the\nrightmost dial/column is incremented for each result, moving left each time a\ndial rolls over, and halting when the leftmost dial rolls over, e.g.:\n\n```javascript\nenumerate([[0, 1], [0, 1]]) // [[0, 0], [0, 1], [1, 0], [1, 1]]\n```\n\nIn this example, the same alphabet is used for each position. As a shorthand, a\nsingle alphabet can be repeated n times by supplying n as the second argument,\ne.g.:\n\n```javascript\nenumerate([0, 1], 2) // [[0, 0], [0, 1], [1, 0], [1, 1]]\n```\n\n## Why?\n\n\u003e Because we often face problems in which an exhaustive examination of all\n\u003e cases is necessary or desirable.\n\n— Donald Knuth, *The Art of Computer Programming*, Section 7.2.1.1, Generating All \u003ci\u003en\u003c/i\u003e-Tuples.\n\n# EXPORTS\n\n## enumerate\n\n- **Type**:\n  - `\u003cT\u003e(alphabet: T[], length: number) =\u003e Array\u003cT[]\u003e`\n  - `\u003cT\u003e(alphabets: T[][]) =\u003e Array\u003cT[]\u003e`\n- **Alias**: `generate`\n\n```javascript\nimport { enumerate } from '@chocolatey/enumerator'\n\nenumerate([0, 1], 2) // [[0, 0], [0, 1], [1, 0], [1, 1]]\n```\n\nTakes an array of alphabets, or a single alphabet and a length (number of times\nto repeat the alphabet), and returns an array of all the permutations of\nvalues from each alphabet in lexicographical order.\n\nThis is a wrapper around [`enumerator`](#enumerator-1) which gathers the generated\nvalues into an array, i.e. the following are equivalent:\n\n```javascript\nconst array1 = enumerate(...args)\nconst array2 = Array.from(enumerator(...args))\n```\n\n## enumerator\n\n- **Type**:\n  - `\u003cT\u003e(alphabet: T[], length: number) =\u003e Generator\u003cT[]\u003e`\n  - `\u003cT\u003e(alphabets: T[][]) =\u003e Generator\u003cT[]\u003e`\n- **Alias**: `generator`\n\n```javascript\nimport { enumerator } from '@chocolatey/enumerator'\n\nfor (const value of enumerator([0, 1], 2)) {\n    console.log(value) // [0, 0], [0, 1], [1, 0], [1, 1]\n}\n```\n\nTakes an array of alphabets, or a single alphabet and a length (number of times\nto repeat the alphabet), and yields all the permutations of values from each\nalphabet in lexicographical order.\n\n## unfold\n\n- **Type**: `\u003cV\u003e(obj: Record\u003cstring, V | V[]\u003e) =\u003e [string, V][][]`\n\n```javascript\nimport { unfold } from '@chocolatey/enumerator'\n\nconst options = {\n    color: ['black', 'pink'],\n    size: ['small', 'large'],\n    discount: false,\n}\n\nconst alphabets = unfold(options)\n```\n\n```javascript\n[\n    [[\"color\", \"black\"], [\"color\", \"pink\"]], // 0\n    [[\"size\", \"small\"], [\"size\", \"large\"]],  // 1\n    [[\"discount\", false]]                    // 2\n]\n```\n\nTakes a plain object and flattens it into an array of arrays of key/value pairs\nsuitable for use as alphabets. The object is unchanged. The object's values are\ncoerced to arrays, so if a single value is already an array, it will need to be\nwrapped in another array, e.g.:\n\n```javascript\n// before x\nconst data = {\n    loc: [x, y],\n}\n\n// after ✔\nconst data = {\n    loc: [[x, y]],\n}\n```\n\n# EXAMPLES\n\n## Generating passwords\n\nSuppose you've protected a Word document or zipfile with the password\n\"rosebud\", but can't remember if any letters were uppercase, if it was one word\nor two, or if there were any substitutions. A list of candidate passwords can\nbe generated by:\n\n```javascript\nconst alphabets = [\n    ['r', 'R'],\n    ['o', 'O', '0'],\n    ['s', 'S', '5'],\n    ['e', 'E', '3'],\n    ['', ' '],\n    ['b', 'B'],\n    ['u', 'U'],\n    ['d', 'D'],\n]\n\nconst passwords = enumerate(alphabets).map(it =\u003e it.join(''))\n```\n\nThis generates 864 different candidates, including \"rosebud\", \"r053buD\",\n\"Rose Bud\", and \"ROSEBUD\".\n\n## Combining options\n\nAlthough any types can be used as values, a specific task may require some\ndata munging to encode its choices as alphabets. To this end, a helper\nfunction, [`unfold`](#unfold), is available which translates a plain object\ninto an array of alphabets of key/value pairs representing an option or\nfeature.\n\nFor example, if a product is available with the following options:\n\n- color: red, black, pink\n- size: small, medium, large\n\n\\- the permutations can be generated with:\n\n```javascript\nimport { enumerate, unfold } from '@chocolatey/enumerator'\n\nconst options = {\n    color: ['red', 'black', 'pink'],\n    size: ['small', 'medium', 'large'],\n}\n\nconst alphabets = unfold(options)\nconst products = enumerate(alphabets).map(Object.fromEntries)\n```\n\n\\- which yields the following result:\n\n```javascript\n[\n    { color: 'red', size: 'small' },\n    { color: 'red', size: 'medium' },\n    { color: 'red', size: 'large' },\n    { color: 'black', size: 'small' },\n    { color: 'black', size: 'medium' },\n    { color: 'black', size: 'large' },\n    { color: 'pink', size: 'small' },\n    { color: 'pink', size: 'medium' },\n    { color: 'pink', size: 'large' }\n]\n```\n\n# DEVELOPMENT\n\n\u003cdetails\u003e\n\n\u003c!-- TOC:ignore --\u003e\n## NPM Scripts\n\nThe following NPM scripts are available:\n\n- build - compile the library for testing and save to the target directory\n- build:doc - generate the README's TOC (table of contents)\n- build:release - compile the library for release and save to the target directory\n- clean - remove the target directory and its contents\n- rebuild - clean the target directory and recompile the library\n- repl - launch a node REPL with the library loaded\n- test - recompile the library and run the test suite\n- test:run - run the test suite\n- typecheck - sanity check the library's type definitions\n\n\u003c/details\u003e\n\n# COMPATIBILITY\n\n- [Maintained Node.js versions](https://github.com/nodejs/Release#readme) and compatible browsers\n\n# SEE ALSO\n\n\u003c!-- TOC:ignore --\u003e\n## JavaScript\n\n- [@kingjs/enumerable.from-each](https://www.npmjs.com/package/%40kingjs%2Fenumerable.from-each)\n- [@kingjs/odometer](https://www.npmjs.com/package/@kingjs/odometer)\n\n\u003c!-- TOC:ignore --\u003e\n## Perl\n\n- [Algorithm::Odometer::Tiny](https://metacpan.org/pod/Algorithm::Odometer::Tiny)\n\n# VERSION\n\n1.1.1\n\n# AUTHOR\n\n[chocolateboy](https://github.com/chocolateboy)\n\n# COPYRIGHT AND LICENSE\n\nCopyright © 2020-2021 by chocolateboy.\n\nThis is free software; you can redistribute it and/or modify it under the terms\nof the [MIT license](https://opensource.org/licenses/MIT).\n\n[jsDelivr]: https://cdn.jsdelivr.net/npm/@chocolatey/enumerator\n[unpkg]: https://unpkg.com/@chocolatey/enumerator\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchocolateboy%2Fenumerator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchocolateboy%2Fenumerator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchocolateboy%2Fenumerator/lists"}