diff --git a/package.json b/package.json index 80cbfff..2c05cd2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@combinatorics/n-permutations", "description": "Set n-permutations for JavaScript", - "version": "0.0.1", + "version": "0.1.0", "license": "AGPL-3.0", "author": "make-github-pseudonymous-again", "homepage": "https://computational-combinatorics.github.io/n-permutations", diff --git a/src/_permutations.js b/src/_permutations.js new file mode 100644 index 0000000..25db354 --- /dev/null +++ b/src/_permutations.js @@ -0,0 +1,51 @@ +import assert from 'assert'; +import {_take} from '@iterable-iterator/slice'; + +import {list} from '@iterable-iterator/list'; +import { + forwardRangeIterator, + backwardRangeIterator, +} from '@iterable-iterator/range'; + +/** + * Yields all k-permutations of {0, 1, ..., n-1}. + * + * @param {number} n + * @param {number} k + * @returns {IterableIterator>} + */ +export default function* _permutations(n, k) { + assert(Number.isInteger(k) && k >= 0); + if (k > n) return; + + const indices = list(forwardRangeIterator(0, n, 1)); + const cycles = list(backwardRangeIterator(n, n - k, -1)); + + yield _take(indices, k); + + if (k === 0 || n === 0) return; + + while (true) { + let i = k; + + while (i--) { + --cycles[i]; + + if (cycles[i] === 0) { + // Could be costly + indices.push(indices.splice(i, 1)[0]); + + cycles[i] = n - i; + } else { + const j = cycles[i]; + + [indices[i], indices[n - j]] = [indices[n - j], indices[i]]; + + yield _take(indices, k); + break; + } + } + + if (i === -1) return; + } +} diff --git a/src/index.js b/src/index.js index 6dd94d7..6e892ad 100644 --- a/src/index.js +++ b/src/index.js @@ -1 +1,2 @@ +export {default as _permutations} from './_permutations.js'; export {default as permutations} from './permutations.js'; diff --git a/src/permutations.js b/src/permutations.js index c65e54c..70d2921 100644 --- a/src/permutations.js +++ b/src/permutations.js @@ -1,9 +1,7 @@ -import assert from 'assert'; -import {_take} from '@iterable-iterator/slice'; - import {list} from '@iterable-iterator/list'; -import {pick} from '@iterable-iterator/map'; -import {range} from '@iterable-iterator/range'; +import {map, pick} from '@iterable-iterator/map'; + +import _permutations from './_permutations.js'; /** * Yields all permutations of each possible choice of r elements @@ -21,48 +19,12 @@ import {range} from '@iterable-iterator/range'; * @param {number} r - The size of the permutations to generate. * @returns {IterableIterator} */ -export default function* permutations(iterable, r) { - assert(Number.isInteger(r) && r >= 0); +const permutations = (iterable, r) => { const pool = list(iterable); + return map( + (indices) => list(pick(pool, indices)), + _permutations(pool.length, r), + ); +}; - const length = pool.length; - - if (r > length) { - return; - } - - const indices = list(range(0, length, 1)); - const cycles = list(range(length, length - r, -1)); - - yield list(pick(pool, _take(indices, r))); - - if (r === 0 || length === 0) { - return; - } - - while (true) { - let i = r; - - while (i--) { - --cycles[i]; - - if (cycles[i] === 0) { - // Could be costly - indices.push(indices.splice(i, 1)[0]); - - cycles[i] = length - i; - } else { - const j = cycles[i]; - - [indices[i], indices[length - j]] = [indices[length - j], indices[i]]; - - yield list(pick(pool, _take(indices, r))); - break; - } - } - - if (i === -1) { - return; - } - } -} +export default permutations; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy